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::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
  253struct InlineValueCache {
  254    enabled: bool,
  255    inlays: Vec<InlayId>,
  256    refresh_task: Task<Option<()>>,
  257}
  258
  259impl InlineValueCache {
  260    fn new(enabled: bool) -> Self {
  261        Self {
  262            enabled,
  263            inlays: Vec::new(),
  264            refresh_task: Task::ready(None),
  265        }
  266    }
  267}
  268
  269#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  270pub enum InlayId {
  271    EditPrediction(usize),
  272    DebuggerValue(usize),
  273    // LSP
  274    Hint(usize),
  275    Color(usize),
  276}
  277
  278impl InlayId {
  279    fn id(&self) -> usize {
  280        match self {
  281            Self::EditPrediction(id) => *id,
  282            Self::DebuggerValue(id) => *id,
  283            Self::Hint(id) => *id,
  284            Self::Color(id) => *id,
  285        }
  286    }
  287}
  288
  289pub enum ActiveDebugLine {}
  290pub enum DebugStackFrameLine {}
  291enum DocumentHighlightRead {}
  292enum DocumentHighlightWrite {}
  293enum InputComposition {}
  294pub enum PendingInput {}
  295enum SelectedTextHighlight {}
  296
  297pub enum ConflictsOuter {}
  298pub enum ConflictsOurs {}
  299pub enum ConflictsTheirs {}
  300pub enum ConflictsOursMarker {}
  301pub enum ConflictsTheirsMarker {}
  302
  303#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  304pub enum Navigated {
  305    Yes,
  306    No,
  307}
  308
  309impl Navigated {
  310    pub fn from_bool(yes: bool) -> Navigated {
  311        if yes { Navigated::Yes } else { Navigated::No }
  312    }
  313}
  314
  315#[derive(Debug, Clone, PartialEq, Eq)]
  316enum DisplayDiffHunk {
  317    Folded {
  318        display_row: DisplayRow,
  319    },
  320    Unfolded {
  321        is_created_file: bool,
  322        diff_base_byte_range: Range<usize>,
  323        display_row_range: Range<DisplayRow>,
  324        multi_buffer_range: Range<Anchor>,
  325        status: DiffHunkStatus,
  326    },
  327}
  328
  329pub enum HideMouseCursorOrigin {
  330    TypingAction,
  331    MovementAction,
  332}
  333
  334pub fn init_settings(cx: &mut App) {
  335    EditorSettings::register(cx);
  336}
  337
  338pub fn init(cx: &mut App) {
  339    init_settings(cx);
  340
  341    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  342
  343    workspace::register_project_item::<Editor>(cx);
  344    workspace::FollowableViewRegistry::register::<Editor>(cx);
  345    workspace::register_serializable_item::<Editor>(cx);
  346
  347    cx.observe_new(
  348        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  349            workspace.register_action(Editor::new_file);
  350            workspace.register_action(Editor::new_file_vertical);
  351            workspace.register_action(Editor::new_file_horizontal);
  352            workspace.register_action(Editor::cancel_language_server_work);
  353            workspace.register_action(Editor::toggle_focus);
  354        },
  355    )
  356    .detach();
  357
  358    cx.on_action(move |_: &workspace::NewFile, cx| {
  359        let app_state = workspace::AppState::global(cx);
  360        if let Some(app_state) = app_state.upgrade() {
  361            workspace::open_new(
  362                Default::default(),
  363                app_state,
  364                cx,
  365                |workspace, window, cx| {
  366                    Editor::new_file(workspace, &Default::default(), window, cx)
  367                },
  368            )
  369            .detach();
  370        }
  371    });
  372    cx.on_action(move |_: &workspace::NewWindow, cx| {
  373        let app_state = workspace::AppState::global(cx);
  374        if let Some(app_state) = app_state.upgrade() {
  375            workspace::open_new(
  376                Default::default(),
  377                app_state,
  378                cx,
  379                |workspace, window, cx| {
  380                    cx.activate(true);
  381                    Editor::new_file(workspace, &Default::default(), window, cx)
  382                },
  383            )
  384            .detach();
  385        }
  386    });
  387}
  388
  389pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  390    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  391}
  392
  393pub trait DiagnosticRenderer {
  394    fn render_group(
  395        &self,
  396        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  397        buffer_id: BufferId,
  398        snapshot: EditorSnapshot,
  399        editor: WeakEntity<Editor>,
  400        cx: &mut App,
  401    ) -> Vec<BlockProperties<Anchor>>;
  402
  403    fn render_hover(
  404        &self,
  405        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  406        range: Range<Point>,
  407        buffer_id: BufferId,
  408        cx: &mut App,
  409    ) -> Option<Entity<markdown::Markdown>>;
  410
  411    fn open_link(
  412        &self,
  413        editor: &mut Editor,
  414        link: SharedString,
  415        window: &mut Window,
  416        cx: &mut Context<Editor>,
  417    );
  418}
  419
  420pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  421
  422impl GlobalDiagnosticRenderer {
  423    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  424        cx.try_global::<Self>().map(|g| g.0.clone())
  425    }
  426}
  427
  428impl gpui::Global for GlobalDiagnosticRenderer {}
  429pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  430    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  431}
  432
  433pub struct SearchWithinRange;
  434
  435trait InvalidationRegion {
  436    fn ranges(&self) -> &[Range<Anchor>];
  437}
  438
  439#[derive(Clone, Debug, PartialEq)]
  440pub enum SelectPhase {
  441    Begin {
  442        position: DisplayPoint,
  443        add: bool,
  444        click_count: usize,
  445    },
  446    BeginColumnar {
  447        position: DisplayPoint,
  448        reset: bool,
  449        mode: ColumnarMode,
  450        goal_column: u32,
  451    },
  452    Extend {
  453        position: DisplayPoint,
  454        click_count: usize,
  455    },
  456    Update {
  457        position: DisplayPoint,
  458        goal_column: u32,
  459        scroll_delta: gpui::Point<f32>,
  460    },
  461    End,
  462}
  463
  464#[derive(Clone, Debug, PartialEq)]
  465pub enum ColumnarMode {
  466    FromMouse,
  467    FromSelection,
  468}
  469
  470#[derive(Clone, Debug)]
  471pub enum SelectMode {
  472    Character,
  473    Word(Range<Anchor>),
  474    Line(Range<Anchor>),
  475    All,
  476}
  477
  478#[derive(Clone, PartialEq, Eq, Debug)]
  479pub enum EditorMode {
  480    SingleLine,
  481    AutoHeight {
  482        min_lines: usize,
  483        max_lines: Option<usize>,
  484    },
  485    Full {
  486        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  487        scale_ui_elements_with_buffer_font_size: bool,
  488        /// When set to `true`, the editor will render a background for the active line.
  489        show_active_line_background: bool,
  490        /// When set to `true`, the editor's height will be determined by its content.
  491        sized_by_content: bool,
  492    },
  493    Minimap {
  494        parent: WeakEntity<Editor>,
  495    },
  496}
  497
  498impl EditorMode {
  499    pub fn full() -> Self {
  500        Self::Full {
  501            scale_ui_elements_with_buffer_font_size: true,
  502            show_active_line_background: true,
  503            sized_by_content: false,
  504        }
  505    }
  506
  507    #[inline]
  508    pub fn is_full(&self) -> bool {
  509        matches!(self, Self::Full { .. })
  510    }
  511
  512    #[inline]
  513    pub fn is_single_line(&self) -> bool {
  514        matches!(self, Self::SingleLine { .. })
  515    }
  516
  517    #[inline]
  518    fn is_minimap(&self) -> bool {
  519        matches!(self, Self::Minimap { .. })
  520    }
  521}
  522
  523#[derive(Copy, Clone, Debug)]
  524pub enum SoftWrap {
  525    /// Prefer not to wrap at all.
  526    ///
  527    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  528    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  529    GitDiff,
  530    /// Prefer a single line generally, unless an overly long line is encountered.
  531    None,
  532    /// Soft wrap lines that exceed the editor width.
  533    EditorWidth,
  534    /// Soft wrap lines at the preferred line length.
  535    Column(u32),
  536    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  537    Bounded(u32),
  538}
  539
  540#[derive(Clone)]
  541pub struct EditorStyle {
  542    pub background: Hsla,
  543    pub border: Hsla,
  544    pub local_player: PlayerColor,
  545    pub text: TextStyle,
  546    pub scrollbar_width: Pixels,
  547    pub syntax: Arc<SyntaxTheme>,
  548    pub status: StatusColors,
  549    pub inlay_hints_style: HighlightStyle,
  550    pub edit_prediction_styles: EditPredictionStyles,
  551    pub unnecessary_code_fade: f32,
  552    pub show_underlines: bool,
  553}
  554
  555impl Default for EditorStyle {
  556    fn default() -> Self {
  557        Self {
  558            background: Hsla::default(),
  559            border: Hsla::default(),
  560            local_player: PlayerColor::default(),
  561            text: TextStyle::default(),
  562            scrollbar_width: Pixels::default(),
  563            syntax: Default::default(),
  564            // HACK: Status colors don't have a real default.
  565            // We should look into removing the status colors from the editor
  566            // style and retrieve them directly from the theme.
  567            status: StatusColors::dark(),
  568            inlay_hints_style: HighlightStyle::default(),
  569            edit_prediction_styles: EditPredictionStyles {
  570                insertion: HighlightStyle::default(),
  571                whitespace: HighlightStyle::default(),
  572            },
  573            unnecessary_code_fade: Default::default(),
  574            show_underlines: true,
  575        }
  576    }
  577}
  578
  579pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  580    let show_background = language_settings::language_settings(None, None, cx)
  581        .inlay_hints
  582        .show_background;
  583
  584    HighlightStyle {
  585        color: Some(cx.theme().status().hint),
  586        background_color: show_background.then(|| cx.theme().status().hint_background),
  587        ..HighlightStyle::default()
  588    }
  589}
  590
  591pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  592    EditPredictionStyles {
  593        insertion: HighlightStyle {
  594            color: Some(cx.theme().status().predictive),
  595            ..HighlightStyle::default()
  596        },
  597        whitespace: HighlightStyle {
  598            background_color: Some(cx.theme().status().created_background),
  599            ..HighlightStyle::default()
  600        },
  601    }
  602}
  603
  604type CompletionId = usize;
  605
  606pub(crate) enum EditDisplayMode {
  607    TabAccept,
  608    DiffPopover,
  609    Inline,
  610}
  611
  612enum EditPrediction {
  613    Edit {
  614        edits: Vec<(Range<Anchor>, String)>,
  615        edit_preview: Option<EditPreview>,
  616        display_mode: EditDisplayMode,
  617        snapshot: BufferSnapshot,
  618    },
  619    Move {
  620        target: Anchor,
  621        snapshot: BufferSnapshot,
  622    },
  623}
  624
  625struct EditPredictionState {
  626    inlay_ids: Vec<InlayId>,
  627    completion: EditPrediction,
  628    completion_id: Option<SharedString>,
  629    invalidation_range: Range<Anchor>,
  630}
  631
  632enum EditPredictionSettings {
  633    Disabled,
  634    Enabled {
  635        show_in_menu: bool,
  636        preview_requires_modifier: bool,
  637    },
  638}
  639
  640enum EditPredictionHighlight {}
  641
  642#[derive(Debug, Clone)]
  643struct InlineDiagnostic {
  644    message: SharedString,
  645    group_id: usize,
  646    is_primary: bool,
  647    start: Point,
  648    severity: lsp::DiagnosticSeverity,
  649}
  650
  651pub enum MenuEditPredictionsPolicy {
  652    Never,
  653    ByProvider,
  654}
  655
  656pub enum EditPredictionPreview {
  657    /// Modifier is not pressed
  658    Inactive { released_too_fast: bool },
  659    /// Modifier pressed
  660    Active {
  661        since: Instant,
  662        previous_scroll_position: Option<ScrollAnchor>,
  663    },
  664}
  665
  666impl EditPredictionPreview {
  667    pub fn released_too_fast(&self) -> bool {
  668        match self {
  669            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  670            EditPredictionPreview::Active { .. } => false,
  671        }
  672    }
  673
  674    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  675        if let EditPredictionPreview::Active {
  676            previous_scroll_position,
  677            ..
  678        } = self
  679        {
  680            *previous_scroll_position = scroll_position;
  681        }
  682    }
  683}
  684
  685pub struct ContextMenuOptions {
  686    pub min_entries_visible: usize,
  687    pub max_entries_visible: usize,
  688    pub placement: Option<ContextMenuPlacement>,
  689}
  690
  691#[derive(Debug, Clone, PartialEq, Eq)]
  692pub enum ContextMenuPlacement {
  693    Above,
  694    Below,
  695}
  696
  697#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  698struct EditorActionId(usize);
  699
  700impl EditorActionId {
  701    pub fn post_inc(&mut self) -> Self {
  702        let answer = self.0;
  703
  704        *self = Self(answer + 1);
  705
  706        Self(answer)
  707    }
  708}
  709
  710// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  711// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  712
  713type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  714type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  715
  716#[derive(Default)]
  717struct ScrollbarMarkerState {
  718    scrollbar_size: Size<Pixels>,
  719    dirty: bool,
  720    markers: Arc<[PaintQuad]>,
  721    pending_refresh: Option<Task<Result<()>>>,
  722}
  723
  724impl ScrollbarMarkerState {
  725    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  726        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  727    }
  728}
  729
  730#[derive(Clone, Copy, PartialEq, Eq)]
  731pub enum MinimapVisibility {
  732    Disabled,
  733    Enabled {
  734        /// The configuration currently present in the users settings.
  735        setting_configuration: bool,
  736        /// Whether to override the currently set visibility from the users setting.
  737        toggle_override: bool,
  738    },
  739}
  740
  741impl MinimapVisibility {
  742    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  743        if mode.is_full() {
  744            Self::Enabled {
  745                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  746                toggle_override: false,
  747            }
  748        } else {
  749            Self::Disabled
  750        }
  751    }
  752
  753    fn hidden(&self) -> Self {
  754        match *self {
  755            Self::Enabled {
  756                setting_configuration,
  757                ..
  758            } => Self::Enabled {
  759                setting_configuration,
  760                toggle_override: setting_configuration,
  761            },
  762            Self::Disabled => Self::Disabled,
  763        }
  764    }
  765
  766    fn disabled(&self) -> bool {
  767        match *self {
  768            Self::Disabled => true,
  769            _ => false,
  770        }
  771    }
  772
  773    fn settings_visibility(&self) -> bool {
  774        match *self {
  775            Self::Enabled {
  776                setting_configuration,
  777                ..
  778            } => setting_configuration,
  779            _ => false,
  780        }
  781    }
  782
  783    fn visible(&self) -> bool {
  784        match *self {
  785            Self::Enabled {
  786                setting_configuration,
  787                toggle_override,
  788            } => setting_configuration ^ toggle_override,
  789            _ => false,
  790        }
  791    }
  792
  793    fn toggle_visibility(&self) -> Self {
  794        match *self {
  795            Self::Enabled {
  796                toggle_override,
  797                setting_configuration,
  798            } => Self::Enabled {
  799                setting_configuration,
  800                toggle_override: !toggle_override,
  801            },
  802            Self::Disabled => Self::Disabled,
  803        }
  804    }
  805}
  806
  807#[derive(Clone, Debug)]
  808struct RunnableTasks {
  809    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  810    offset: multi_buffer::Anchor,
  811    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  812    column: u32,
  813    // Values of all named captures, including those starting with '_'
  814    extra_variables: HashMap<String, String>,
  815    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  816    context_range: Range<BufferOffset>,
  817}
  818
  819impl RunnableTasks {
  820    fn resolve<'a>(
  821        &'a self,
  822        cx: &'a task::TaskContext,
  823    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  824        self.templates.iter().filter_map(|(kind, template)| {
  825            template
  826                .resolve_task(&kind.to_id_base(), cx)
  827                .map(|task| (kind.clone(), task))
  828        })
  829    }
  830}
  831
  832#[derive(Clone)]
  833pub struct ResolvedTasks {
  834    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  835    position: Anchor,
  836}
  837
  838#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  839struct BufferOffset(usize);
  840
  841// Addons allow storing per-editor state in other crates (e.g. Vim)
  842pub trait Addon: 'static {
  843    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  844
  845    fn render_buffer_header_controls(
  846        &self,
  847        _: &ExcerptInfo,
  848        _: &Window,
  849        _: &App,
  850    ) -> Option<AnyElement> {
  851        None
  852    }
  853
  854    fn to_any(&self) -> &dyn std::any::Any;
  855
  856    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  857        None
  858    }
  859}
  860
  861struct ChangeLocation {
  862    current: Option<Vec<Anchor>>,
  863    original: Vec<Anchor>,
  864}
  865impl ChangeLocation {
  866    fn locations(&self) -> &[Anchor] {
  867        self.current.as_ref().unwrap_or(&self.original)
  868    }
  869}
  870
  871/// A set of caret positions, registered when the editor was edited.
  872pub struct ChangeList {
  873    changes: Vec<ChangeLocation>,
  874    /// Currently "selected" change.
  875    position: Option<usize>,
  876}
  877
  878impl ChangeList {
  879    pub fn new() -> Self {
  880        Self {
  881            changes: Vec::new(),
  882            position: None,
  883        }
  884    }
  885
  886    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  887    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  888    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  889        if self.changes.is_empty() {
  890            return None;
  891        }
  892
  893        let prev = self.position.unwrap_or(self.changes.len());
  894        let next = if direction == Direction::Prev {
  895            prev.saturating_sub(count)
  896        } else {
  897            (prev + count).min(self.changes.len() - 1)
  898        };
  899        self.position = Some(next);
  900        self.changes.get(next).map(|change| change.locations())
  901    }
  902
  903    /// Adds a new change to the list, resetting the change list position.
  904    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  905        self.position.take();
  906        if let Some(last) = self.changes.last_mut()
  907            && group
  908        {
  909            last.current = Some(new_positions)
  910        } else {
  911            self.changes.push(ChangeLocation {
  912                original: new_positions,
  913                current: None,
  914            });
  915        }
  916    }
  917
  918    pub fn last(&self) -> Option<&[Anchor]> {
  919        self.changes.last().map(|change| change.locations())
  920    }
  921
  922    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  923        self.changes.last().map(|change| change.original.as_slice())
  924    }
  925
  926    pub fn invert_last_group(&mut self) {
  927        if let Some(last) = self.changes.last_mut() {
  928            if let Some(current) = last.current.as_mut() {
  929                mem::swap(&mut last.original, current);
  930            }
  931        }
  932    }
  933}
  934
  935#[derive(Clone)]
  936struct InlineBlamePopoverState {
  937    scroll_handle: ScrollHandle,
  938    commit_message: Option<ParsedCommitMessage>,
  939    markdown: Entity<Markdown>,
  940}
  941
  942struct InlineBlamePopover {
  943    position: gpui::Point<Pixels>,
  944    hide_task: Option<Task<()>>,
  945    popover_bounds: Option<Bounds<Pixels>>,
  946    popover_state: InlineBlamePopoverState,
  947    keyboard_grace: bool,
  948}
  949
  950enum SelectionDragState {
  951    /// State when no drag related activity is detected.
  952    None,
  953    /// State when the mouse is down on a selection that is about to be dragged.
  954    ReadyToDrag {
  955        selection: Selection<Anchor>,
  956        click_position: gpui::Point<Pixels>,
  957        mouse_down_time: Instant,
  958    },
  959    /// State when the mouse is dragging the selection in the editor.
  960    Dragging {
  961        selection: Selection<Anchor>,
  962        drop_cursor: Selection<Anchor>,
  963        hide_drop_cursor: bool,
  964    },
  965}
  966
  967enum ColumnarSelectionState {
  968    FromMouse {
  969        selection_tail: Anchor,
  970        display_point: Option<DisplayPoint>,
  971    },
  972    FromSelection {
  973        selection_tail: Anchor,
  974    },
  975}
  976
  977/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  978/// a breakpoint on them.
  979#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  980struct PhantomBreakpointIndicator {
  981    display_row: DisplayRow,
  982    /// There's a small debounce between hovering over the line and showing the indicator.
  983    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  984    is_active: bool,
  985    collides_with_existing_breakpoint: bool,
  986}
  987
  988/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  989///
  990/// See the [module level documentation](self) for more information.
  991pub struct Editor {
  992    focus_handle: FocusHandle,
  993    last_focused_descendant: Option<WeakFocusHandle>,
  994    /// The text buffer being edited
  995    buffer: Entity<MultiBuffer>,
  996    /// Map of how text in the buffer should be displayed.
  997    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  998    pub display_map: Entity<DisplayMap>,
  999    pub selections: SelectionsCollection,
 1000    pub scroll_manager: ScrollManager,
 1001    /// When inline assist editors are linked, they all render cursors because
 1002    /// typing enters text into each of them, even the ones that aren't focused.
 1003    pub(crate) show_cursor_when_unfocused: bool,
 1004    columnar_selection_state: Option<ColumnarSelectionState>,
 1005    add_selections_state: Option<AddSelectionsState>,
 1006    select_next_state: Option<SelectNextState>,
 1007    select_prev_state: Option<SelectNextState>,
 1008    selection_history: SelectionHistory,
 1009    defer_selection_effects: bool,
 1010    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1011    autoclose_regions: Vec<AutocloseRegion>,
 1012    snippet_stack: InvalidationStack<SnippetState>,
 1013    select_syntax_node_history: SelectSyntaxNodeHistory,
 1014    ime_transaction: Option<TransactionId>,
 1015    pub diagnostics_max_severity: DiagnosticSeverity,
 1016    active_diagnostics: ActiveDiagnostic,
 1017    show_inline_diagnostics: bool,
 1018    inline_diagnostics_update: Task<()>,
 1019    inline_diagnostics_enabled: bool,
 1020    diagnostics_enabled: bool,
 1021    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1022    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1023    hard_wrap: Option<usize>,
 1024
 1025    // TODO: make this a access method
 1026    pub project: Option<Entity<Project>>,
 1027    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1028    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1029    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1030    blink_manager: Entity<BlinkManager>,
 1031    show_cursor_names: bool,
 1032    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1033    pub show_local_selections: bool,
 1034    mode: EditorMode,
 1035    show_breadcrumbs: bool,
 1036    show_gutter: bool,
 1037    show_scrollbars: ScrollbarAxes,
 1038    minimap_visibility: MinimapVisibility,
 1039    offset_content: bool,
 1040    disable_expand_excerpt_buttons: bool,
 1041    show_line_numbers: Option<bool>,
 1042    use_relative_line_numbers: Option<bool>,
 1043    show_git_diff_gutter: Option<bool>,
 1044    show_code_actions: Option<bool>,
 1045    show_runnables: Option<bool>,
 1046    show_breakpoints: Option<bool>,
 1047    show_wrap_guides: Option<bool>,
 1048    show_indent_guides: Option<bool>,
 1049    placeholder_text: Option<Arc<str>>,
 1050    highlight_order: usize,
 1051    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1052    background_highlights: TreeMap<HighlightKey, BackgroundHighlight>,
 1053    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1054    scrollbar_marker_state: ScrollbarMarkerState,
 1055    active_indent_guides_state: ActiveIndentGuidesState,
 1056    nav_history: Option<ItemNavHistory>,
 1057    context_menu: RefCell<Option<CodeContextMenu>>,
 1058    context_menu_options: Option<ContextMenuOptions>,
 1059    mouse_context_menu: Option<MouseContextMenu>,
 1060    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1061    inline_blame_popover: Option<InlineBlamePopover>,
 1062    inline_blame_popover_show_task: Option<Task<()>>,
 1063    signature_help_state: SignatureHelpState,
 1064    auto_signature_help: Option<bool>,
 1065    find_all_references_task_sources: Vec<Anchor>,
 1066    next_completion_id: CompletionId,
 1067    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1068    code_actions_task: Option<Task<Result<()>>>,
 1069    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1070    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1071    document_highlights_task: Option<Task<()>>,
 1072    linked_editing_range_task: Option<Task<Option<()>>>,
 1073    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1074    pending_rename: Option<RenameState>,
 1075    searchable: bool,
 1076    cursor_shape: CursorShape,
 1077    current_line_highlight: Option<CurrentLineHighlight>,
 1078    collapse_matches: bool,
 1079    autoindent_mode: Option<AutoindentMode>,
 1080    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1081    input_enabled: bool,
 1082    use_modal_editing: bool,
 1083    read_only: bool,
 1084    leader_id: Option<CollaboratorId>,
 1085    remote_id: Option<ViewId>,
 1086    pub hover_state: HoverState,
 1087    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1088    gutter_hovered: bool,
 1089    hovered_link_state: Option<HoveredLinkState>,
 1090    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1091    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1092    active_edit_prediction: Option<EditPredictionState>,
 1093    /// Used to prevent flickering as the user types while the menu is open
 1094    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1095    edit_prediction_settings: EditPredictionSettings,
 1096    edit_predictions_hidden_for_vim_mode: bool,
 1097    show_edit_predictions_override: Option<bool>,
 1098    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1099    edit_prediction_preview: EditPredictionPreview,
 1100    edit_prediction_indent_conflict: bool,
 1101    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1102    inlay_hint_cache: InlayHintCache,
 1103    next_inlay_id: usize,
 1104    _subscriptions: Vec<Subscription>,
 1105    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1106    gutter_dimensions: GutterDimensions,
 1107    style: Option<EditorStyle>,
 1108    text_style_refinement: Option<TextStyleRefinement>,
 1109    next_editor_action_id: EditorActionId,
 1110    editor_actions: Rc<
 1111        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1112    >,
 1113    use_autoclose: bool,
 1114    use_auto_surround: bool,
 1115    auto_replace_emoji_shortcode: bool,
 1116    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1117    show_git_blame_gutter: bool,
 1118    show_git_blame_inline: bool,
 1119    show_git_blame_inline_delay_task: Option<Task<()>>,
 1120    git_blame_inline_enabled: bool,
 1121    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1122    serialize_dirty_buffers: bool,
 1123    show_selection_menu: Option<bool>,
 1124    blame: Option<Entity<GitBlame>>,
 1125    blame_subscription: Option<Subscription>,
 1126    custom_context_menu: Option<
 1127        Box<
 1128            dyn 'static
 1129                + Fn(
 1130                    &mut Self,
 1131                    DisplayPoint,
 1132                    &mut Window,
 1133                    &mut Context<Self>,
 1134                ) -> Option<Entity<ui::ContextMenu>>,
 1135        >,
 1136    >,
 1137    last_bounds: Option<Bounds<Pixels>>,
 1138    last_position_map: Option<Rc<PositionMap>>,
 1139    expect_bounds_change: Option<Bounds<Pixels>>,
 1140    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1141    tasks_update_task: Option<Task<()>>,
 1142    breakpoint_store: Option<Entity<BreakpointStore>>,
 1143    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1144    hovered_diff_hunk_row: Option<DisplayRow>,
 1145    pull_diagnostics_task: Task<()>,
 1146    in_project_search: bool,
 1147    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1148    breadcrumb_header: Option<String>,
 1149    focused_block: Option<FocusedBlock>,
 1150    next_scroll_position: NextScrollCursorCenterTopBottom,
 1151    addons: HashMap<TypeId, Box<dyn Addon>>,
 1152    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1153    load_diff_task: Option<Shared<Task<()>>>,
 1154    /// Whether we are temporarily displaying a diff other than git's
 1155    temporary_diff_override: bool,
 1156    selection_mark_mode: bool,
 1157    toggle_fold_multiple_buffers: Task<()>,
 1158    _scroll_cursor_center_top_bottom_task: Task<()>,
 1159    serialize_selections: Task<()>,
 1160    serialize_folds: Task<()>,
 1161    mouse_cursor_hidden: bool,
 1162    minimap: Option<Entity<Self>>,
 1163    hide_mouse_mode: HideMouseMode,
 1164    pub change_list: ChangeList,
 1165    inline_value_cache: InlineValueCache,
 1166    selection_drag_state: SelectionDragState,
 1167    next_color_inlay_id: usize,
 1168    colors: Option<LspColorData>,
 1169    folding_newlines: Task<()>,
 1170}
 1171
 1172#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1173enum NextScrollCursorCenterTopBottom {
 1174    #[default]
 1175    Center,
 1176    Top,
 1177    Bottom,
 1178}
 1179
 1180impl NextScrollCursorCenterTopBottom {
 1181    fn next(&self) -> Self {
 1182        match self {
 1183            Self::Center => Self::Top,
 1184            Self::Top => Self::Bottom,
 1185            Self::Bottom => Self::Center,
 1186        }
 1187    }
 1188}
 1189
 1190#[derive(Clone)]
 1191pub struct EditorSnapshot {
 1192    pub mode: EditorMode,
 1193    show_gutter: bool,
 1194    show_line_numbers: Option<bool>,
 1195    show_git_diff_gutter: Option<bool>,
 1196    show_code_actions: Option<bool>,
 1197    show_runnables: Option<bool>,
 1198    show_breakpoints: Option<bool>,
 1199    git_blame_gutter_max_author_length: Option<usize>,
 1200    pub display_snapshot: DisplaySnapshot,
 1201    pub placeholder_text: Option<Arc<str>>,
 1202    is_focused: bool,
 1203    scroll_anchor: ScrollAnchor,
 1204    ongoing_scroll: OngoingScroll,
 1205    current_line_highlight: CurrentLineHighlight,
 1206    gutter_hovered: bool,
 1207}
 1208
 1209#[derive(Default, Debug, Clone, Copy)]
 1210pub struct GutterDimensions {
 1211    pub left_padding: Pixels,
 1212    pub right_padding: Pixels,
 1213    pub width: Pixels,
 1214    pub margin: Pixels,
 1215    pub git_blame_entries_width: Option<Pixels>,
 1216}
 1217
 1218impl GutterDimensions {
 1219    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1220        Self {
 1221            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1222            ..Default::default()
 1223        }
 1224    }
 1225
 1226    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1227        -cx.text_system().descent(font_id, font_size)
 1228    }
 1229    /// The full width of the space taken up by the gutter.
 1230    pub fn full_width(&self) -> Pixels {
 1231        self.margin + self.width
 1232    }
 1233
 1234    /// The width of the space reserved for the fold indicators,
 1235    /// use alongside 'justify_end' and `gutter_width` to
 1236    /// right align content with the line numbers
 1237    pub fn fold_area_width(&self) -> Pixels {
 1238        self.margin + self.right_padding
 1239    }
 1240}
 1241
 1242struct CharacterDimensions {
 1243    em_width: Pixels,
 1244    em_advance: Pixels,
 1245    line_height: Pixels,
 1246}
 1247
 1248#[derive(Debug)]
 1249pub struct RemoteSelection {
 1250    pub replica_id: ReplicaId,
 1251    pub selection: Selection<Anchor>,
 1252    pub cursor_shape: CursorShape,
 1253    pub collaborator_id: CollaboratorId,
 1254    pub line_mode: bool,
 1255    pub user_name: Option<SharedString>,
 1256    pub color: PlayerColor,
 1257}
 1258
 1259#[derive(Clone, Debug)]
 1260struct SelectionHistoryEntry {
 1261    selections: Arc<[Selection<Anchor>]>,
 1262    select_next_state: Option<SelectNextState>,
 1263    select_prev_state: Option<SelectNextState>,
 1264    add_selections_state: Option<AddSelectionsState>,
 1265}
 1266
 1267#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1268enum SelectionHistoryMode {
 1269    Normal,
 1270    Undoing,
 1271    Redoing,
 1272    Skipping,
 1273}
 1274
 1275#[derive(Clone, PartialEq, Eq, Hash)]
 1276struct HoveredCursor {
 1277    replica_id: u16,
 1278    selection_id: usize,
 1279}
 1280
 1281impl Default for SelectionHistoryMode {
 1282    fn default() -> Self {
 1283        Self::Normal
 1284    }
 1285}
 1286
 1287#[derive(Debug)]
 1288/// SelectionEffects controls the side-effects of updating the selection.
 1289///
 1290/// The default behaviour does "what you mostly want":
 1291/// - it pushes to the nav history if the cursor moved by >10 lines
 1292/// - it re-triggers completion requests
 1293/// - it scrolls to fit
 1294///
 1295/// You might want to modify these behaviours. For example when doing a "jump"
 1296/// like go to definition, we always want to add to nav history; but when scrolling
 1297/// in vim mode we never do.
 1298///
 1299/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1300/// move.
 1301#[derive(Clone)]
 1302pub struct SelectionEffects {
 1303    nav_history: Option<bool>,
 1304    completions: bool,
 1305    scroll: Option<Autoscroll>,
 1306}
 1307
 1308impl Default for SelectionEffects {
 1309    fn default() -> Self {
 1310        Self {
 1311            nav_history: None,
 1312            completions: true,
 1313            scroll: Some(Autoscroll::fit()),
 1314        }
 1315    }
 1316}
 1317impl SelectionEffects {
 1318    pub fn scroll(scroll: Autoscroll) -> Self {
 1319        Self {
 1320            scroll: Some(scroll),
 1321            ..Default::default()
 1322        }
 1323    }
 1324
 1325    pub fn no_scroll() -> Self {
 1326        Self {
 1327            scroll: None,
 1328            ..Default::default()
 1329        }
 1330    }
 1331
 1332    pub fn completions(self, completions: bool) -> Self {
 1333        Self {
 1334            completions,
 1335            ..self
 1336        }
 1337    }
 1338
 1339    pub fn nav_history(self, nav_history: bool) -> Self {
 1340        Self {
 1341            nav_history: Some(nav_history),
 1342            ..self
 1343        }
 1344    }
 1345}
 1346
 1347struct DeferredSelectionEffectsState {
 1348    changed: bool,
 1349    effects: SelectionEffects,
 1350    old_cursor_position: Anchor,
 1351    history_entry: SelectionHistoryEntry,
 1352}
 1353
 1354#[derive(Default)]
 1355struct SelectionHistory {
 1356    #[allow(clippy::type_complexity)]
 1357    selections_by_transaction:
 1358        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1359    mode: SelectionHistoryMode,
 1360    undo_stack: VecDeque<SelectionHistoryEntry>,
 1361    redo_stack: VecDeque<SelectionHistoryEntry>,
 1362}
 1363
 1364impl SelectionHistory {
 1365    #[track_caller]
 1366    fn insert_transaction(
 1367        &mut self,
 1368        transaction_id: TransactionId,
 1369        selections: Arc<[Selection<Anchor>]>,
 1370    ) {
 1371        if selections.is_empty() {
 1372            log::error!(
 1373                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1374                std::panic::Location::caller()
 1375            );
 1376            return;
 1377        }
 1378        self.selections_by_transaction
 1379            .insert(transaction_id, (selections, None));
 1380    }
 1381
 1382    #[allow(clippy::type_complexity)]
 1383    fn transaction(
 1384        &self,
 1385        transaction_id: TransactionId,
 1386    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1387        self.selections_by_transaction.get(&transaction_id)
 1388    }
 1389
 1390    #[allow(clippy::type_complexity)]
 1391    fn transaction_mut(
 1392        &mut self,
 1393        transaction_id: TransactionId,
 1394    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1395        self.selections_by_transaction.get_mut(&transaction_id)
 1396    }
 1397
 1398    fn push(&mut self, entry: SelectionHistoryEntry) {
 1399        if !entry.selections.is_empty() {
 1400            match self.mode {
 1401                SelectionHistoryMode::Normal => {
 1402                    self.push_undo(entry);
 1403                    self.redo_stack.clear();
 1404                }
 1405                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1406                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1407                SelectionHistoryMode::Skipping => {}
 1408            }
 1409        }
 1410    }
 1411
 1412    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1413        if self
 1414            .undo_stack
 1415            .back()
 1416            .map_or(true, |e| e.selections != entry.selections)
 1417        {
 1418            self.undo_stack.push_back(entry);
 1419            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1420                self.undo_stack.pop_front();
 1421            }
 1422        }
 1423    }
 1424
 1425    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1426        if self
 1427            .redo_stack
 1428            .back()
 1429            .map_or(true, |e| e.selections != entry.selections)
 1430        {
 1431            self.redo_stack.push_back(entry);
 1432            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1433                self.redo_stack.pop_front();
 1434            }
 1435        }
 1436    }
 1437}
 1438
 1439#[derive(Clone, Copy)]
 1440pub struct RowHighlightOptions {
 1441    pub autoscroll: bool,
 1442    pub include_gutter: bool,
 1443}
 1444
 1445impl Default for RowHighlightOptions {
 1446    fn default() -> Self {
 1447        Self {
 1448            autoscroll: Default::default(),
 1449            include_gutter: true,
 1450        }
 1451    }
 1452}
 1453
 1454struct RowHighlight {
 1455    index: usize,
 1456    range: Range<Anchor>,
 1457    color: Hsla,
 1458    options: RowHighlightOptions,
 1459    type_id: TypeId,
 1460}
 1461
 1462#[derive(Clone, Debug)]
 1463struct AddSelectionsState {
 1464    groups: Vec<AddSelectionsGroup>,
 1465}
 1466
 1467#[derive(Clone, Debug)]
 1468struct AddSelectionsGroup {
 1469    above: bool,
 1470    stack: Vec<usize>,
 1471}
 1472
 1473#[derive(Clone)]
 1474struct SelectNextState {
 1475    query: AhoCorasick,
 1476    wordwise: bool,
 1477    done: bool,
 1478}
 1479
 1480impl std::fmt::Debug for SelectNextState {
 1481    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1482        f.debug_struct(std::any::type_name::<Self>())
 1483            .field("wordwise", &self.wordwise)
 1484            .field("done", &self.done)
 1485            .finish()
 1486    }
 1487}
 1488
 1489#[derive(Debug)]
 1490struct AutocloseRegion {
 1491    selection_id: usize,
 1492    range: Range<Anchor>,
 1493    pair: BracketPair,
 1494}
 1495
 1496#[derive(Debug)]
 1497struct SnippetState {
 1498    ranges: Vec<Vec<Range<Anchor>>>,
 1499    active_index: usize,
 1500    choices: Vec<Option<Vec<String>>>,
 1501}
 1502
 1503#[doc(hidden)]
 1504pub struct RenameState {
 1505    pub range: Range<Anchor>,
 1506    pub old_name: Arc<str>,
 1507    pub editor: Entity<Editor>,
 1508    block_id: CustomBlockId,
 1509}
 1510
 1511struct InvalidationStack<T>(Vec<T>);
 1512
 1513struct RegisteredEditPredictionProvider {
 1514    provider: Arc<dyn EditPredictionProviderHandle>,
 1515    _subscription: Subscription,
 1516}
 1517
 1518#[derive(Debug, PartialEq, Eq)]
 1519pub struct ActiveDiagnosticGroup {
 1520    pub active_range: Range<Anchor>,
 1521    pub active_message: String,
 1522    pub group_id: usize,
 1523    pub blocks: HashSet<CustomBlockId>,
 1524}
 1525
 1526#[derive(Debug, PartialEq, Eq)]
 1527
 1528pub(crate) enum ActiveDiagnostic {
 1529    None,
 1530    All,
 1531    Group(ActiveDiagnosticGroup),
 1532}
 1533
 1534#[derive(Serialize, Deserialize, Clone, Debug)]
 1535pub struct ClipboardSelection {
 1536    /// The number of bytes in this selection.
 1537    pub len: usize,
 1538    /// Whether this was a full-line selection.
 1539    pub is_entire_line: bool,
 1540    /// The indentation of the first line when this content was originally copied.
 1541    pub first_line_indent: u32,
 1542}
 1543
 1544// selections, scroll behavior, was newest selection reversed
 1545type SelectSyntaxNodeHistoryState = (
 1546    Box<[Selection<usize>]>,
 1547    SelectSyntaxNodeScrollBehavior,
 1548    bool,
 1549);
 1550
 1551#[derive(Default)]
 1552struct SelectSyntaxNodeHistory {
 1553    stack: Vec<SelectSyntaxNodeHistoryState>,
 1554    // disable temporarily to allow changing selections without losing the stack
 1555    pub disable_clearing: bool,
 1556}
 1557
 1558impl SelectSyntaxNodeHistory {
 1559    pub fn try_clear(&mut self) {
 1560        if !self.disable_clearing {
 1561            self.stack.clear();
 1562        }
 1563    }
 1564
 1565    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1566        self.stack.push(selection);
 1567    }
 1568
 1569    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1570        self.stack.pop()
 1571    }
 1572}
 1573
 1574enum SelectSyntaxNodeScrollBehavior {
 1575    CursorTop,
 1576    FitSelection,
 1577    CursorBottom,
 1578}
 1579
 1580#[derive(Debug)]
 1581pub(crate) struct NavigationData {
 1582    cursor_anchor: Anchor,
 1583    cursor_position: Point,
 1584    scroll_anchor: ScrollAnchor,
 1585    scroll_top_row: u32,
 1586}
 1587
 1588#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1589pub enum GotoDefinitionKind {
 1590    Symbol,
 1591    Declaration,
 1592    Type,
 1593    Implementation,
 1594}
 1595
 1596#[derive(Debug, Clone)]
 1597enum InlayHintRefreshReason {
 1598    ModifiersChanged(bool),
 1599    Toggle(bool),
 1600    SettingsChange(InlayHintSettings),
 1601    NewLinesShown,
 1602    BufferEdited(HashSet<Arc<Language>>),
 1603    RefreshRequested,
 1604    ExcerptsRemoved(Vec<ExcerptId>),
 1605}
 1606
 1607impl InlayHintRefreshReason {
 1608    fn description(&self) -> &'static str {
 1609        match self {
 1610            Self::ModifiersChanged(_) => "modifiers changed",
 1611            Self::Toggle(_) => "toggle",
 1612            Self::SettingsChange(_) => "settings change",
 1613            Self::NewLinesShown => "new lines shown",
 1614            Self::BufferEdited(_) => "buffer edited",
 1615            Self::RefreshRequested => "refresh requested",
 1616            Self::ExcerptsRemoved(_) => "excerpts removed",
 1617        }
 1618    }
 1619}
 1620
 1621pub enum FormatTarget {
 1622    Buffers(HashSet<Entity<Buffer>>),
 1623    Ranges(Vec<Range<MultiBufferPoint>>),
 1624}
 1625
 1626pub(crate) struct FocusedBlock {
 1627    id: BlockId,
 1628    focus_handle: WeakFocusHandle,
 1629}
 1630
 1631#[derive(Clone)]
 1632enum JumpData {
 1633    MultiBufferRow {
 1634        row: MultiBufferRow,
 1635        line_offset_from_top: u32,
 1636    },
 1637    MultiBufferPoint {
 1638        excerpt_id: ExcerptId,
 1639        position: Point,
 1640        anchor: text::Anchor,
 1641        line_offset_from_top: u32,
 1642    },
 1643}
 1644
 1645pub enum MultibufferSelectionMode {
 1646    First,
 1647    All,
 1648}
 1649
 1650#[derive(Clone, Copy, Debug, Default)]
 1651pub struct RewrapOptions {
 1652    pub override_language_settings: bool,
 1653    pub preserve_existing_whitespace: bool,
 1654}
 1655
 1656impl Editor {
 1657    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1658        let buffer = cx.new(|cx| Buffer::local("", cx));
 1659        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1660        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1661    }
 1662
 1663    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1664        let buffer = cx.new(|cx| Buffer::local("", cx));
 1665        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1666        Self::new(EditorMode::full(), buffer, None, window, cx)
 1667    }
 1668
 1669    pub fn auto_height(
 1670        min_lines: usize,
 1671        max_lines: usize,
 1672        window: &mut Window,
 1673        cx: &mut Context<Self>,
 1674    ) -> Self {
 1675        let buffer = cx.new(|cx| Buffer::local("", cx));
 1676        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1677        Self::new(
 1678            EditorMode::AutoHeight {
 1679                min_lines,
 1680                max_lines: Some(max_lines),
 1681            },
 1682            buffer,
 1683            None,
 1684            window,
 1685            cx,
 1686        )
 1687    }
 1688
 1689    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1690    /// The editor grows as tall as needed to fit its content.
 1691    pub fn auto_height_unbounded(
 1692        min_lines: usize,
 1693        window: &mut Window,
 1694        cx: &mut Context<Self>,
 1695    ) -> Self {
 1696        let buffer = cx.new(|cx| Buffer::local("", cx));
 1697        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1698        Self::new(
 1699            EditorMode::AutoHeight {
 1700                min_lines,
 1701                max_lines: None,
 1702            },
 1703            buffer,
 1704            None,
 1705            window,
 1706            cx,
 1707        )
 1708    }
 1709
 1710    pub fn for_buffer(
 1711        buffer: Entity<Buffer>,
 1712        project: Option<Entity<Project>>,
 1713        window: &mut Window,
 1714        cx: &mut Context<Self>,
 1715    ) -> Self {
 1716        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1717        Self::new(EditorMode::full(), buffer, project, window, cx)
 1718    }
 1719
 1720    pub fn for_multibuffer(
 1721        buffer: Entity<MultiBuffer>,
 1722        project: Option<Entity<Project>>,
 1723        window: &mut Window,
 1724        cx: &mut Context<Self>,
 1725    ) -> Self {
 1726        Self::new(EditorMode::full(), buffer, project, window, cx)
 1727    }
 1728
 1729    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1730        let mut clone = Self::new(
 1731            self.mode.clone(),
 1732            self.buffer.clone(),
 1733            self.project.clone(),
 1734            window,
 1735            cx,
 1736        );
 1737        self.display_map.update(cx, |display_map, cx| {
 1738            let snapshot = display_map.snapshot(cx);
 1739            clone.display_map.update(cx, |display_map, cx| {
 1740                display_map.set_state(&snapshot, cx);
 1741            });
 1742        });
 1743        clone.folds_did_change(cx);
 1744        clone.selections.clone_state(&self.selections);
 1745        clone.scroll_manager.clone_state(&self.scroll_manager);
 1746        clone.searchable = self.searchable;
 1747        clone.read_only = self.read_only;
 1748        clone
 1749    }
 1750
 1751    pub fn new(
 1752        mode: EditorMode,
 1753        buffer: Entity<MultiBuffer>,
 1754        project: Option<Entity<Project>>,
 1755        window: &mut Window,
 1756        cx: &mut Context<Self>,
 1757    ) -> Self {
 1758        Editor::new_internal(mode, buffer, project, None, window, cx)
 1759    }
 1760
 1761    fn new_internal(
 1762        mode: EditorMode,
 1763        buffer: Entity<MultiBuffer>,
 1764        project: Option<Entity<Project>>,
 1765        display_map: Option<Entity<DisplayMap>>,
 1766        window: &mut Window,
 1767        cx: &mut Context<Self>,
 1768    ) -> Self {
 1769        debug_assert!(
 1770            display_map.is_none() || mode.is_minimap(),
 1771            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1772        );
 1773
 1774        let full_mode = mode.is_full();
 1775        let is_minimap = mode.is_minimap();
 1776        let diagnostics_max_severity = if full_mode {
 1777            EditorSettings::get_global(cx)
 1778                .diagnostics_max_severity
 1779                .unwrap_or(DiagnosticSeverity::Hint)
 1780        } else {
 1781            DiagnosticSeverity::Off
 1782        };
 1783        let style = window.text_style();
 1784        let font_size = style.font_size.to_pixels(window.rem_size());
 1785        let editor = cx.entity().downgrade();
 1786        let fold_placeholder = FoldPlaceholder {
 1787            constrain_width: true,
 1788            render: Arc::new(move |fold_id, fold_range, cx| {
 1789                let editor = editor.clone();
 1790                div()
 1791                    .id(fold_id)
 1792                    .bg(cx.theme().colors().ghost_element_background)
 1793                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1794                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1795                    .rounded_xs()
 1796                    .size_full()
 1797                    .cursor_pointer()
 1798                    .child("")
 1799                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1800                    .on_click(move |_, _window, cx| {
 1801                        editor
 1802                            .update(cx, |editor, cx| {
 1803                                editor.unfold_ranges(
 1804                                    &[fold_range.start..fold_range.end],
 1805                                    true,
 1806                                    false,
 1807                                    cx,
 1808                                );
 1809                                cx.stop_propagation();
 1810                            })
 1811                            .ok();
 1812                    })
 1813                    .into_any()
 1814            }),
 1815            merge_adjacent: true,
 1816            ..FoldPlaceholder::default()
 1817        };
 1818        let display_map = display_map.unwrap_or_else(|| {
 1819            cx.new(|cx| {
 1820                DisplayMap::new(
 1821                    buffer.clone(),
 1822                    style.font(),
 1823                    font_size,
 1824                    None,
 1825                    FILE_HEADER_HEIGHT,
 1826                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1827                    fold_placeholder,
 1828                    diagnostics_max_severity,
 1829                    cx,
 1830                )
 1831            })
 1832        });
 1833
 1834        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1835
 1836        let blink_manager = cx.new(|cx| {
 1837            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1838            if is_minimap {
 1839                blink_manager.disable(cx);
 1840            }
 1841            blink_manager
 1842        });
 1843
 1844        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1845            .then(|| language_settings::SoftWrap::None);
 1846
 1847        let mut project_subscriptions = Vec::new();
 1848        if full_mode {
 1849            if let Some(project) = project.as_ref() {
 1850                project_subscriptions.push(cx.subscribe_in(
 1851                    project,
 1852                    window,
 1853                    |editor, _, event, window, cx| match event {
 1854                        project::Event::RefreshCodeLens => {
 1855                            // we always query lens with actions, without storing them, always refreshing them
 1856                        }
 1857                        project::Event::RefreshInlayHints => {
 1858                            editor
 1859                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1860                        }
 1861                        project::Event::LanguageServerAdded(..)
 1862                        | project::Event::LanguageServerRemoved(..) => {
 1863                            if editor.tasks_update_task.is_none() {
 1864                                editor.tasks_update_task =
 1865                                    Some(editor.refresh_runnables(window, cx));
 1866                            }
 1867                        }
 1868                        project::Event::SnippetEdit(id, snippet_edits) => {
 1869                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1870                                let focus_handle = editor.focus_handle(cx);
 1871                                if focus_handle.is_focused(window) {
 1872                                    let snapshot = buffer.read(cx).snapshot();
 1873                                    for (range, snippet) in snippet_edits {
 1874                                        let editor_range =
 1875                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1876                                        editor
 1877                                            .insert_snippet(
 1878                                                &[editor_range],
 1879                                                snippet.clone(),
 1880                                                window,
 1881                                                cx,
 1882                                            )
 1883                                            .ok();
 1884                                    }
 1885                                }
 1886                            }
 1887                        }
 1888                        project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1889                            if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1890                                editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1891                            }
 1892                        }
 1893                        _ => {}
 1894                    },
 1895                ));
 1896                if let Some(task_inventory) = project
 1897                    .read(cx)
 1898                    .task_store()
 1899                    .read(cx)
 1900                    .task_inventory()
 1901                    .cloned()
 1902                {
 1903                    project_subscriptions.push(cx.observe_in(
 1904                        &task_inventory,
 1905                        window,
 1906                        |editor, _, window, cx| {
 1907                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1908                        },
 1909                    ));
 1910                };
 1911
 1912                project_subscriptions.push(cx.subscribe_in(
 1913                    &project.read(cx).breakpoint_store(),
 1914                    window,
 1915                    |editor, _, event, window, cx| match event {
 1916                        BreakpointStoreEvent::ClearDebugLines => {
 1917                            editor.clear_row_highlights::<ActiveDebugLine>();
 1918                            editor.refresh_inline_values(cx);
 1919                        }
 1920                        BreakpointStoreEvent::SetDebugLine => {
 1921                            if editor.go_to_active_debug_line(window, cx) {
 1922                                cx.stop_propagation();
 1923                            }
 1924
 1925                            editor.refresh_inline_values(cx);
 1926                        }
 1927                        _ => {}
 1928                    },
 1929                ));
 1930                let git_store = project.read(cx).git_store().clone();
 1931                let project = project.clone();
 1932                project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1933                    match event {
 1934                        GitStoreEvent::RepositoryUpdated(
 1935                            _,
 1936                            RepositoryEvent::Updated {
 1937                                new_instance: true, ..
 1938                            },
 1939                            _,
 1940                        ) => {
 1941                            this.load_diff_task = Some(
 1942                                update_uncommitted_diff_for_buffer(
 1943                                    cx.entity(),
 1944                                    &project,
 1945                                    this.buffer.read(cx).all_buffers(),
 1946                                    this.buffer.clone(),
 1947                                    cx,
 1948                                )
 1949                                .shared(),
 1950                            );
 1951                        }
 1952                        _ => {}
 1953                    }
 1954                }));
 1955            }
 1956        }
 1957
 1958        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1959
 1960        let inlay_hint_settings =
 1961            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1962        let focus_handle = cx.focus_handle();
 1963        if !is_minimap {
 1964            cx.on_focus(&focus_handle, window, Self::handle_focus)
 1965                .detach();
 1966            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1967                .detach();
 1968            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1969                .detach();
 1970            cx.on_blur(&focus_handle, window, Self::handle_blur)
 1971                .detach();
 1972            cx.observe_pending_input(window, Self::observe_pending_input)
 1973                .detach();
 1974        }
 1975
 1976        let show_indent_guides = if matches!(
 1977            mode,
 1978            EditorMode::SingleLine { .. } | EditorMode::Minimap { .. }
 1979        ) {
 1980            Some(false)
 1981        } else {
 1982            None
 1983        };
 1984
 1985        let breakpoint_store = match (&mode, project.as_ref()) {
 1986            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1987            _ => None,
 1988        };
 1989
 1990        let mut code_action_providers = Vec::new();
 1991        let mut load_uncommitted_diff = None;
 1992        if let Some(project) = project.clone() {
 1993            load_uncommitted_diff = Some(
 1994                update_uncommitted_diff_for_buffer(
 1995                    cx.entity(),
 1996                    &project,
 1997                    buffer.read(cx).all_buffers(),
 1998                    buffer.clone(),
 1999                    cx,
 2000                )
 2001                .shared(),
 2002            );
 2003            code_action_providers.push(Rc::new(project) as Rc<_>);
 2004        }
 2005
 2006        let mut editor = Self {
 2007            focus_handle,
 2008            show_cursor_when_unfocused: false,
 2009            last_focused_descendant: None,
 2010            buffer: buffer.clone(),
 2011            display_map: display_map.clone(),
 2012            selections,
 2013            scroll_manager: ScrollManager::new(cx),
 2014            columnar_selection_state: None,
 2015            add_selections_state: None,
 2016            select_next_state: None,
 2017            select_prev_state: None,
 2018            selection_history: SelectionHistory::default(),
 2019            defer_selection_effects: false,
 2020            deferred_selection_effects_state: None,
 2021            autoclose_regions: Vec::new(),
 2022            snippet_stack: InvalidationStack::default(),
 2023            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2024            ime_transaction: None,
 2025            active_diagnostics: ActiveDiagnostic::None,
 2026            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2027            inline_diagnostics_update: Task::ready(()),
 2028            inline_diagnostics: Vec::new(),
 2029            soft_wrap_mode_override,
 2030            diagnostics_max_severity,
 2031            hard_wrap: None,
 2032            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2033            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2034            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2035            project,
 2036            blink_manager: blink_manager.clone(),
 2037            show_local_selections: true,
 2038            show_scrollbars: ScrollbarAxes {
 2039                horizontal: full_mode,
 2040                vertical: full_mode,
 2041            },
 2042            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2043            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 2044            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2045            show_gutter: full_mode,
 2046            show_line_numbers: (!full_mode).then_some(false),
 2047            use_relative_line_numbers: None,
 2048            disable_expand_excerpt_buttons: !full_mode,
 2049            show_git_diff_gutter: None,
 2050            show_code_actions: None,
 2051            show_runnables: None,
 2052            show_breakpoints: None,
 2053            show_wrap_guides: None,
 2054            show_indent_guides,
 2055            placeholder_text: None,
 2056            highlight_order: 0,
 2057            highlighted_rows: HashMap::default(),
 2058            background_highlights: TreeMap::default(),
 2059            gutter_highlights: TreeMap::default(),
 2060            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2061            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2062            nav_history: None,
 2063            context_menu: RefCell::new(None),
 2064            context_menu_options: None,
 2065            mouse_context_menu: None,
 2066            completion_tasks: Vec::new(),
 2067            inline_blame_popover: None,
 2068            inline_blame_popover_show_task: None,
 2069            signature_help_state: SignatureHelpState::default(),
 2070            auto_signature_help: None,
 2071            find_all_references_task_sources: Vec::new(),
 2072            next_completion_id: 0,
 2073            next_inlay_id: 0,
 2074            code_action_providers,
 2075            available_code_actions: None,
 2076            code_actions_task: None,
 2077            quick_selection_highlight_task: None,
 2078            debounced_selection_highlight_task: None,
 2079            document_highlights_task: None,
 2080            linked_editing_range_task: None,
 2081            pending_rename: None,
 2082            searchable: !is_minimap,
 2083            cursor_shape: EditorSettings::get_global(cx)
 2084                .cursor_shape
 2085                .unwrap_or_default(),
 2086            current_line_highlight: None,
 2087            autoindent_mode: Some(AutoindentMode::EachLine),
 2088            collapse_matches: false,
 2089            workspace: None,
 2090            input_enabled: !is_minimap,
 2091            use_modal_editing: full_mode,
 2092            read_only: is_minimap,
 2093            use_autoclose: true,
 2094            use_auto_surround: true,
 2095            auto_replace_emoji_shortcode: false,
 2096            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2097            leader_id: None,
 2098            remote_id: None,
 2099            hover_state: HoverState::default(),
 2100            pending_mouse_down: None,
 2101            hovered_link_state: None,
 2102            edit_prediction_provider: None,
 2103            active_edit_prediction: None,
 2104            stale_edit_prediction_in_menu: None,
 2105            edit_prediction_preview: EditPredictionPreview::Inactive {
 2106                released_too_fast: false,
 2107            },
 2108            inline_diagnostics_enabled: full_mode,
 2109            diagnostics_enabled: full_mode,
 2110            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2111            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2112            gutter_hovered: false,
 2113            pixel_position_of_newest_cursor: None,
 2114            last_bounds: None,
 2115            last_position_map: None,
 2116            expect_bounds_change: None,
 2117            gutter_dimensions: GutterDimensions::default(),
 2118            style: None,
 2119            show_cursor_names: false,
 2120            hovered_cursors: HashMap::default(),
 2121            next_editor_action_id: EditorActionId::default(),
 2122            editor_actions: Rc::default(),
 2123            edit_predictions_hidden_for_vim_mode: false,
 2124            show_edit_predictions_override: None,
 2125            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2126            edit_prediction_settings: EditPredictionSettings::Disabled,
 2127            edit_prediction_indent_conflict: false,
 2128            edit_prediction_requires_modifier_in_indent_conflict: true,
 2129            custom_context_menu: None,
 2130            show_git_blame_gutter: false,
 2131            show_git_blame_inline: false,
 2132            show_selection_menu: None,
 2133            show_git_blame_inline_delay_task: None,
 2134            git_blame_inline_enabled: full_mode
 2135                && ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2136            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2137            serialize_dirty_buffers: !is_minimap
 2138                && ProjectSettings::get_global(cx)
 2139                    .session
 2140                    .restore_unsaved_buffers,
 2141            blame: None,
 2142            blame_subscription: None,
 2143            tasks: BTreeMap::default(),
 2144
 2145            breakpoint_store,
 2146            gutter_breakpoint_indicator: (None, None),
 2147            hovered_diff_hunk_row: None,
 2148            _subscriptions: (!is_minimap)
 2149                .then(|| {
 2150                    vec![
 2151                        cx.observe(&buffer, Self::on_buffer_changed),
 2152                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2153                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2154                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2155                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2156                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2157                        cx.observe_window_activation(window, |editor, window, cx| {
 2158                            let active = window.is_window_active();
 2159                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2160                                if active {
 2161                                    blink_manager.enable(cx);
 2162                                } else {
 2163                                    blink_manager.disable(cx);
 2164                                }
 2165                            });
 2166                            if active {
 2167                                editor.show_mouse_cursor(cx);
 2168                            }
 2169                        }),
 2170                    ]
 2171                })
 2172                .unwrap_or_default(),
 2173            tasks_update_task: None,
 2174            pull_diagnostics_task: Task::ready(()),
 2175            colors: None,
 2176            next_color_inlay_id: 0,
 2177            linked_edit_ranges: Default::default(),
 2178            in_project_search: false,
 2179            previous_search_ranges: None,
 2180            breadcrumb_header: None,
 2181            focused_block: None,
 2182            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2183            addons: HashMap::default(),
 2184            registered_buffers: HashMap::default(),
 2185            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2186            selection_mark_mode: false,
 2187            toggle_fold_multiple_buffers: Task::ready(()),
 2188            serialize_selections: Task::ready(()),
 2189            serialize_folds: Task::ready(()),
 2190            text_style_refinement: None,
 2191            load_diff_task: load_uncommitted_diff,
 2192            temporary_diff_override: false,
 2193            mouse_cursor_hidden: false,
 2194            minimap: None,
 2195            hide_mouse_mode: EditorSettings::get_global(cx)
 2196                .hide_mouse
 2197                .unwrap_or_default(),
 2198            change_list: ChangeList::new(),
 2199            mode,
 2200            selection_drag_state: SelectionDragState::None,
 2201            folding_newlines: Task::ready(()),
 2202        };
 2203
 2204        if is_minimap {
 2205            return editor;
 2206        }
 2207
 2208        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2209            editor
 2210                ._subscriptions
 2211                .push(cx.observe(breakpoints, |_, _, cx| {
 2212                    cx.notify();
 2213                }));
 2214        }
 2215        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2216        editor._subscriptions.extend(project_subscriptions);
 2217
 2218        editor._subscriptions.push(cx.subscribe_in(
 2219            &cx.entity(),
 2220            window,
 2221            |editor, _, e: &EditorEvent, window, cx| match e {
 2222                EditorEvent::ScrollPositionChanged { local, .. } => {
 2223                    if *local {
 2224                        let new_anchor = editor.scroll_manager.anchor();
 2225                        let snapshot = editor.snapshot(window, cx);
 2226                        editor.update_restoration_data(cx, move |data| {
 2227                            data.scroll_position = (
 2228                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2229                                new_anchor.offset,
 2230                            );
 2231                        });
 2232                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2233                        editor.inline_blame_popover.take();
 2234                    }
 2235                }
 2236                EditorEvent::Edited { .. } => {
 2237                    if !vim_enabled(cx) {
 2238                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2239                        let pop_state = editor
 2240                            .change_list
 2241                            .last()
 2242                            .map(|previous| {
 2243                                previous.len() == selections.len()
 2244                                    && previous.iter().enumerate().all(|(ix, p)| {
 2245                                        p.to_display_point(&map).row()
 2246                                            == selections[ix].head().row()
 2247                                    })
 2248                            })
 2249                            .unwrap_or(false);
 2250                        let new_positions = selections
 2251                            .into_iter()
 2252                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2253                            .collect();
 2254                        editor
 2255                            .change_list
 2256                            .push_to_change_list(pop_state, new_positions);
 2257                    }
 2258                }
 2259                _ => (),
 2260            },
 2261        ));
 2262
 2263        if let Some(dap_store) = editor
 2264            .project
 2265            .as_ref()
 2266            .map(|project| project.read(cx).dap_store())
 2267        {
 2268            let weak_editor = cx.weak_entity();
 2269
 2270            editor
 2271                ._subscriptions
 2272                .push(
 2273                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2274                        let session_entity = cx.entity();
 2275                        weak_editor
 2276                            .update(cx, |editor, cx| {
 2277                                editor._subscriptions.push(
 2278                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2279                                );
 2280                            })
 2281                            .ok();
 2282                    }),
 2283                );
 2284
 2285            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2286                editor
 2287                    ._subscriptions
 2288                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2289            }
 2290        }
 2291
 2292        // skip adding the initial selection to selection history
 2293        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2294        editor.end_selection(window, cx);
 2295        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2296
 2297        editor.scroll_manager.show_scrollbars(window, cx);
 2298        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2299
 2300        if full_mode {
 2301            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2302            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2303
 2304            if editor.git_blame_inline_enabled {
 2305                editor.start_git_blame_inline(false, window, cx);
 2306            }
 2307
 2308            editor.go_to_active_debug_line(window, cx);
 2309
 2310            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2311                if let Some(project) = editor.project.as_ref() {
 2312                    let handle = project.update(cx, |project, cx| {
 2313                        project.register_buffer_with_language_servers(&buffer, cx)
 2314                    });
 2315                    editor
 2316                        .registered_buffers
 2317                        .insert(buffer.read(cx).remote_id(), handle);
 2318                }
 2319            }
 2320
 2321            editor.minimap =
 2322                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2323            editor.colors = Some(LspColorData::new(cx));
 2324            editor.update_lsp_data(false, None, window, cx);
 2325        }
 2326
 2327        if editor.mode.is_full() {
 2328            editor.report_editor_event("Editor Opened", None, cx);
 2329        }
 2330
 2331        editor
 2332    }
 2333
 2334    pub fn deploy_mouse_context_menu(
 2335        &mut self,
 2336        position: gpui::Point<Pixels>,
 2337        context_menu: Entity<ContextMenu>,
 2338        window: &mut Window,
 2339        cx: &mut Context<Self>,
 2340    ) {
 2341        self.mouse_context_menu = Some(MouseContextMenu::new(
 2342            self,
 2343            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2344            context_menu,
 2345            window,
 2346            cx,
 2347        ));
 2348    }
 2349
 2350    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2351        self.mouse_context_menu
 2352            .as_ref()
 2353            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2354    }
 2355
 2356    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2357        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2358    }
 2359
 2360    fn key_context_internal(
 2361        &self,
 2362        has_active_edit_prediction: bool,
 2363        window: &Window,
 2364        cx: &App,
 2365    ) -> KeyContext {
 2366        let mut key_context = KeyContext::new_with_defaults();
 2367        key_context.add("Editor");
 2368        let mode = match self.mode {
 2369            EditorMode::SingleLine { .. } => "single_line",
 2370            EditorMode::AutoHeight { .. } => "auto_height",
 2371            EditorMode::Minimap { .. } => "minimap",
 2372            EditorMode::Full { .. } => "full",
 2373        };
 2374
 2375        if EditorSettings::jupyter_enabled(cx) {
 2376            key_context.add("jupyter");
 2377        }
 2378
 2379        key_context.set("mode", mode);
 2380        if self.pending_rename.is_some() {
 2381            key_context.add("renaming");
 2382        }
 2383
 2384        match self.context_menu.borrow().as_ref() {
 2385            Some(CodeContextMenu::Completions(menu)) => {
 2386                if menu.visible() {
 2387                    key_context.add("menu");
 2388                    key_context.add("showing_completions");
 2389                }
 2390            }
 2391            Some(CodeContextMenu::CodeActions(menu)) => {
 2392                if menu.visible() {
 2393                    key_context.add("menu");
 2394                    key_context.add("showing_code_actions")
 2395                }
 2396            }
 2397            None => {}
 2398        }
 2399
 2400        if self.signature_help_state.has_multiple_signatures() {
 2401            key_context.add("showing_signature_help");
 2402        }
 2403
 2404        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2405        if !self.focus_handle(cx).contains_focused(window, cx)
 2406            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2407        {
 2408            for addon in self.addons.values() {
 2409                addon.extend_key_context(&mut key_context, cx)
 2410            }
 2411        }
 2412
 2413        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2414            if let Some(extension) = singleton_buffer
 2415                .read(cx)
 2416                .file()
 2417                .and_then(|file| file.path().extension()?.to_str())
 2418            {
 2419                key_context.set("extension", extension.to_string());
 2420            }
 2421        } else {
 2422            key_context.add("multibuffer");
 2423        }
 2424
 2425        if has_active_edit_prediction {
 2426            if self.edit_prediction_in_conflict() {
 2427                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2428            } else {
 2429                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2430                key_context.add("copilot_suggestion");
 2431            }
 2432        }
 2433
 2434        if self.selection_mark_mode {
 2435            key_context.add("selection_mode");
 2436        }
 2437
 2438        key_context
 2439    }
 2440
 2441    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2442        if self.mouse_cursor_hidden {
 2443            self.mouse_cursor_hidden = false;
 2444            cx.notify();
 2445        }
 2446    }
 2447
 2448    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2449        let hide_mouse_cursor = match origin {
 2450            HideMouseCursorOrigin::TypingAction => {
 2451                matches!(
 2452                    self.hide_mouse_mode,
 2453                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2454                )
 2455            }
 2456            HideMouseCursorOrigin::MovementAction => {
 2457                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2458            }
 2459        };
 2460        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2461            self.mouse_cursor_hidden = hide_mouse_cursor;
 2462            cx.notify();
 2463        }
 2464    }
 2465
 2466    pub fn edit_prediction_in_conflict(&self) -> bool {
 2467        if !self.show_edit_predictions_in_menu() {
 2468            return false;
 2469        }
 2470
 2471        let showing_completions = self
 2472            .context_menu
 2473            .borrow()
 2474            .as_ref()
 2475            .map_or(false, |context| {
 2476                matches!(context, CodeContextMenu::Completions(_))
 2477            });
 2478
 2479        showing_completions
 2480            || self.edit_prediction_requires_modifier()
 2481            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2482            // bindings to insert tab characters.
 2483            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2484    }
 2485
 2486    pub fn accept_edit_prediction_keybind(
 2487        &self,
 2488        accept_partial: bool,
 2489        window: &Window,
 2490        cx: &App,
 2491    ) -> AcceptEditPredictionBinding {
 2492        let key_context = self.key_context_internal(true, window, cx);
 2493        let in_conflict = self.edit_prediction_in_conflict();
 2494
 2495        let bindings = if accept_partial {
 2496            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2497        } else {
 2498            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2499        };
 2500
 2501        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2502        // just the first one.
 2503        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2504            !in_conflict
 2505                || binding
 2506                    .keystrokes()
 2507                    .first()
 2508                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2509        }))
 2510    }
 2511
 2512    pub fn new_file(
 2513        workspace: &mut Workspace,
 2514        _: &workspace::NewFile,
 2515        window: &mut Window,
 2516        cx: &mut Context<Workspace>,
 2517    ) {
 2518        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2519            "Failed to create buffer",
 2520            window,
 2521            cx,
 2522            |e, _, _| match e.error_code() {
 2523                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2524                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2525                e.error_tag("required").unwrap_or("the latest version")
 2526            )),
 2527                _ => None,
 2528            },
 2529        );
 2530    }
 2531
 2532    pub fn new_in_workspace(
 2533        workspace: &mut Workspace,
 2534        window: &mut Window,
 2535        cx: &mut Context<Workspace>,
 2536    ) -> Task<Result<Entity<Editor>>> {
 2537        let project = workspace.project().clone();
 2538        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2539
 2540        cx.spawn_in(window, async move |workspace, cx| {
 2541            let buffer = create.await?;
 2542            workspace.update_in(cx, |workspace, window, cx| {
 2543                let editor =
 2544                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2545                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2546                editor
 2547            })
 2548        })
 2549    }
 2550
 2551    fn new_file_vertical(
 2552        workspace: &mut Workspace,
 2553        _: &workspace::NewFileSplitVertical,
 2554        window: &mut Window,
 2555        cx: &mut Context<Workspace>,
 2556    ) {
 2557        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2558    }
 2559
 2560    fn new_file_horizontal(
 2561        workspace: &mut Workspace,
 2562        _: &workspace::NewFileSplitHorizontal,
 2563        window: &mut Window,
 2564        cx: &mut Context<Workspace>,
 2565    ) {
 2566        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2567    }
 2568
 2569    fn new_file_in_direction(
 2570        workspace: &mut Workspace,
 2571        direction: SplitDirection,
 2572        window: &mut Window,
 2573        cx: &mut Context<Workspace>,
 2574    ) {
 2575        let project = workspace.project().clone();
 2576        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2577
 2578        cx.spawn_in(window, async move |workspace, cx| {
 2579            let buffer = create.await?;
 2580            workspace.update_in(cx, move |workspace, window, cx| {
 2581                workspace.split_item(
 2582                    direction,
 2583                    Box::new(
 2584                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2585                    ),
 2586                    window,
 2587                    cx,
 2588                )
 2589            })?;
 2590            anyhow::Ok(())
 2591        })
 2592        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2593            match e.error_code() {
 2594                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2595                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2596                e.error_tag("required").unwrap_or("the latest version")
 2597            )),
 2598                _ => None,
 2599            }
 2600        });
 2601    }
 2602
 2603    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2604        self.leader_id
 2605    }
 2606
 2607    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2608        &self.buffer
 2609    }
 2610
 2611    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2612        self.workspace.as_ref()?.0.upgrade()
 2613    }
 2614
 2615    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2616        self.buffer().read(cx).title(cx)
 2617    }
 2618
 2619    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2620        let git_blame_gutter_max_author_length = self
 2621            .render_git_blame_gutter(cx)
 2622            .then(|| {
 2623                if let Some(blame) = self.blame.as_ref() {
 2624                    let max_author_length =
 2625                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2626                    Some(max_author_length)
 2627                } else {
 2628                    None
 2629                }
 2630            })
 2631            .flatten();
 2632
 2633        EditorSnapshot {
 2634            mode: self.mode.clone(),
 2635            show_gutter: self.show_gutter,
 2636            show_line_numbers: self.show_line_numbers,
 2637            show_git_diff_gutter: self.show_git_diff_gutter,
 2638            show_code_actions: self.show_code_actions,
 2639            show_runnables: self.show_runnables,
 2640            show_breakpoints: self.show_breakpoints,
 2641            git_blame_gutter_max_author_length,
 2642            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2643            scroll_anchor: self.scroll_manager.anchor(),
 2644            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2645            placeholder_text: self.placeholder_text.clone(),
 2646            is_focused: self.focus_handle.is_focused(window),
 2647            current_line_highlight: self
 2648                .current_line_highlight
 2649                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2650            gutter_hovered: self.gutter_hovered,
 2651        }
 2652    }
 2653
 2654    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2655        self.buffer.read(cx).language_at(point, cx)
 2656    }
 2657
 2658    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2659        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2660    }
 2661
 2662    pub fn active_excerpt(
 2663        &self,
 2664        cx: &App,
 2665    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2666        self.buffer
 2667            .read(cx)
 2668            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2669    }
 2670
 2671    pub fn mode(&self) -> &EditorMode {
 2672        &self.mode
 2673    }
 2674
 2675    pub fn set_mode(&mut self, mode: EditorMode) {
 2676        self.mode = mode;
 2677    }
 2678
 2679    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2680        self.collaboration_hub.as_deref()
 2681    }
 2682
 2683    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2684        self.collaboration_hub = Some(hub);
 2685    }
 2686
 2687    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2688        self.in_project_search = in_project_search;
 2689    }
 2690
 2691    pub fn set_custom_context_menu(
 2692        &mut self,
 2693        f: impl 'static
 2694        + Fn(
 2695            &mut Self,
 2696            DisplayPoint,
 2697            &mut Window,
 2698            &mut Context<Self>,
 2699        ) -> Option<Entity<ui::ContextMenu>>,
 2700    ) {
 2701        self.custom_context_menu = Some(Box::new(f))
 2702    }
 2703
 2704    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2705        self.completion_provider = provider;
 2706    }
 2707
 2708    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2709        self.semantics_provider.clone()
 2710    }
 2711
 2712    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2713        self.semantics_provider = provider;
 2714    }
 2715
 2716    pub fn set_edit_prediction_provider<T>(
 2717        &mut self,
 2718        provider: Option<Entity<T>>,
 2719        window: &mut Window,
 2720        cx: &mut Context<Self>,
 2721    ) where
 2722        T: EditPredictionProvider,
 2723    {
 2724        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2725            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2726                if this.focus_handle.is_focused(window) {
 2727                    this.update_visible_edit_prediction(window, cx);
 2728                }
 2729            }),
 2730            provider: Arc::new(provider),
 2731        });
 2732        self.update_edit_prediction_settings(cx);
 2733        self.refresh_edit_prediction(false, false, window, cx);
 2734    }
 2735
 2736    pub fn placeholder_text(&self) -> Option<&str> {
 2737        self.placeholder_text.as_deref()
 2738    }
 2739
 2740    pub fn set_placeholder_text(
 2741        &mut self,
 2742        placeholder_text: impl Into<Arc<str>>,
 2743        cx: &mut Context<Self>,
 2744    ) {
 2745        let placeholder_text = Some(placeholder_text.into());
 2746        if self.placeholder_text != placeholder_text {
 2747            self.placeholder_text = placeholder_text;
 2748            cx.notify();
 2749        }
 2750    }
 2751
 2752    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2753        self.cursor_shape = cursor_shape;
 2754
 2755        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2756        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2757
 2758        cx.notify();
 2759    }
 2760
 2761    pub fn set_current_line_highlight(
 2762        &mut self,
 2763        current_line_highlight: Option<CurrentLineHighlight>,
 2764    ) {
 2765        self.current_line_highlight = current_line_highlight;
 2766    }
 2767
 2768    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2769        self.collapse_matches = collapse_matches;
 2770    }
 2771
 2772    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2773        let buffers = self.buffer.read(cx).all_buffers();
 2774        let Some(project) = self.project.as_ref() else {
 2775            return;
 2776        };
 2777        project.update(cx, |project, cx| {
 2778            for buffer in buffers {
 2779                self.registered_buffers
 2780                    .entry(buffer.read(cx).remote_id())
 2781                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2782            }
 2783        })
 2784    }
 2785
 2786    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2787        if self.collapse_matches {
 2788            return range.start..range.start;
 2789        }
 2790        range.clone()
 2791    }
 2792
 2793    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2794        if self.display_map.read(cx).clip_at_line_ends != clip {
 2795            self.display_map
 2796                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2797        }
 2798    }
 2799
 2800    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2801        self.input_enabled = input_enabled;
 2802    }
 2803
 2804    pub fn set_edit_predictions_hidden_for_vim_mode(
 2805        &mut self,
 2806        hidden: bool,
 2807        window: &mut Window,
 2808        cx: &mut Context<Self>,
 2809    ) {
 2810        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2811            self.edit_predictions_hidden_for_vim_mode = hidden;
 2812            if hidden {
 2813                self.update_visible_edit_prediction(window, cx);
 2814            } else {
 2815                self.refresh_edit_prediction(true, false, window, cx);
 2816            }
 2817        }
 2818    }
 2819
 2820    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2821        self.menu_edit_predictions_policy = value;
 2822    }
 2823
 2824    pub fn set_autoindent(&mut self, autoindent: bool) {
 2825        if autoindent {
 2826            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2827        } else {
 2828            self.autoindent_mode = None;
 2829        }
 2830    }
 2831
 2832    pub fn read_only(&self, cx: &App) -> bool {
 2833        self.read_only || self.buffer.read(cx).read_only()
 2834    }
 2835
 2836    pub fn set_read_only(&mut self, read_only: bool) {
 2837        self.read_only = read_only;
 2838    }
 2839
 2840    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2841        self.use_autoclose = autoclose;
 2842    }
 2843
 2844    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2845        self.use_auto_surround = auto_surround;
 2846    }
 2847
 2848    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2849        self.auto_replace_emoji_shortcode = auto_replace;
 2850    }
 2851
 2852    pub fn toggle_edit_predictions(
 2853        &mut self,
 2854        _: &ToggleEditPrediction,
 2855        window: &mut Window,
 2856        cx: &mut Context<Self>,
 2857    ) {
 2858        if self.show_edit_predictions_override.is_some() {
 2859            self.set_show_edit_predictions(None, window, cx);
 2860        } else {
 2861            let show_edit_predictions = !self.edit_predictions_enabled();
 2862            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2863        }
 2864    }
 2865
 2866    pub fn set_show_edit_predictions(
 2867        &mut self,
 2868        show_edit_predictions: Option<bool>,
 2869        window: &mut Window,
 2870        cx: &mut Context<Self>,
 2871    ) {
 2872        self.show_edit_predictions_override = show_edit_predictions;
 2873        self.update_edit_prediction_settings(cx);
 2874
 2875        if let Some(false) = show_edit_predictions {
 2876            self.discard_edit_prediction(false, cx);
 2877        } else {
 2878            self.refresh_edit_prediction(false, true, window, cx);
 2879        }
 2880    }
 2881
 2882    fn edit_predictions_disabled_in_scope(
 2883        &self,
 2884        buffer: &Entity<Buffer>,
 2885        buffer_position: language::Anchor,
 2886        cx: &App,
 2887    ) -> bool {
 2888        let snapshot = buffer.read(cx).snapshot();
 2889        let settings = snapshot.settings_at(buffer_position, cx);
 2890
 2891        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2892            return false;
 2893        };
 2894
 2895        scope.override_name().map_or(false, |scope_name| {
 2896            settings
 2897                .edit_predictions_disabled_in
 2898                .iter()
 2899                .any(|s| s == scope_name)
 2900        })
 2901    }
 2902
 2903    pub fn set_use_modal_editing(&mut self, to: bool) {
 2904        self.use_modal_editing = to;
 2905    }
 2906
 2907    pub fn use_modal_editing(&self) -> bool {
 2908        self.use_modal_editing
 2909    }
 2910
 2911    fn selections_did_change(
 2912        &mut self,
 2913        local: bool,
 2914        old_cursor_position: &Anchor,
 2915        effects: SelectionEffects,
 2916        window: &mut Window,
 2917        cx: &mut Context<Self>,
 2918    ) {
 2919        window.invalidate_character_coordinates();
 2920
 2921        // Copy selections to primary selection buffer
 2922        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2923        if local {
 2924            let selections = self.selections.all::<usize>(cx);
 2925            let buffer_handle = self.buffer.read(cx).read(cx);
 2926
 2927            let mut text = String::new();
 2928            for (index, selection) in selections.iter().enumerate() {
 2929                let text_for_selection = buffer_handle
 2930                    .text_for_range(selection.start..selection.end)
 2931                    .collect::<String>();
 2932
 2933                text.push_str(&text_for_selection);
 2934                if index != selections.len() - 1 {
 2935                    text.push('\n');
 2936                }
 2937            }
 2938
 2939            if !text.is_empty() {
 2940                cx.write_to_primary(ClipboardItem::new_string(text));
 2941            }
 2942        }
 2943
 2944        let selection_anchors = self.selections.disjoint_anchors();
 2945
 2946        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2947            self.buffer.update(cx, |buffer, cx| {
 2948                buffer.set_active_selections(
 2949                    &selection_anchors,
 2950                    self.selections.line_mode,
 2951                    self.cursor_shape,
 2952                    cx,
 2953                )
 2954            });
 2955        }
 2956        let display_map = self
 2957            .display_map
 2958            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2959        let buffer = &display_map.buffer_snapshot;
 2960        if self.selections.count() == 1 {
 2961            self.add_selections_state = None;
 2962        }
 2963        self.select_next_state = None;
 2964        self.select_prev_state = None;
 2965        self.select_syntax_node_history.try_clear();
 2966        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 2967        self.snippet_stack.invalidate(&selection_anchors, buffer);
 2968        self.take_rename(false, window, cx);
 2969
 2970        let newest_selection = self.selections.newest_anchor();
 2971        let new_cursor_position = newest_selection.head();
 2972        let selection_start = newest_selection.start;
 2973
 2974        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 2975            self.push_to_nav_history(
 2976                *old_cursor_position,
 2977                Some(new_cursor_position.to_point(buffer)),
 2978                false,
 2979                effects.nav_history == Some(true),
 2980                cx,
 2981            );
 2982        }
 2983
 2984        if local {
 2985            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2986                if !self.registered_buffers.contains_key(&buffer_id) {
 2987                    if let Some(project) = self.project.as_ref() {
 2988                        project.update(cx, |project, cx| {
 2989                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2990                                return;
 2991                            };
 2992                            self.registered_buffers.insert(
 2993                                buffer_id,
 2994                                project.register_buffer_with_language_servers(&buffer, cx),
 2995                            );
 2996                        })
 2997                    }
 2998                }
 2999            }
 3000
 3001            let mut context_menu = self.context_menu.borrow_mut();
 3002            let completion_menu = match context_menu.as_ref() {
 3003                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3004                Some(CodeContextMenu::CodeActions(_)) => {
 3005                    *context_menu = None;
 3006                    None
 3007                }
 3008                None => None,
 3009            };
 3010            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3011            drop(context_menu);
 3012
 3013            if effects.completions {
 3014                if let Some(completion_position) = completion_position {
 3015                    let start_offset = selection_start.to_offset(buffer);
 3016                    let position_matches = start_offset == completion_position.to_offset(buffer);
 3017                    let continue_showing = if position_matches {
 3018                        if self.snippet_stack.is_empty() {
 3019                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3020                        } else {
 3021                            // Snippet choices can be shown even when the cursor is in whitespace.
 3022                            // Dismissing the menu with actions like backspace is handled by
 3023                            // invalidation regions.
 3024                            true
 3025                        }
 3026                    } else {
 3027                        false
 3028                    };
 3029
 3030                    if continue_showing {
 3031                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3032                    } else {
 3033                        self.hide_context_menu(window, cx);
 3034                    }
 3035                }
 3036            }
 3037
 3038            hide_hover(self, cx);
 3039
 3040            if old_cursor_position.to_display_point(&display_map).row()
 3041                != new_cursor_position.to_display_point(&display_map).row()
 3042            {
 3043                self.available_code_actions.take();
 3044            }
 3045            self.refresh_code_actions(window, cx);
 3046            self.refresh_document_highlights(cx);
 3047            self.refresh_selected_text_highlights(false, window, cx);
 3048            refresh_matching_bracket_highlights(self, window, cx);
 3049            self.update_visible_edit_prediction(window, cx);
 3050            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3051            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3052            self.inline_blame_popover.take();
 3053            if self.git_blame_inline_enabled {
 3054                self.start_inline_blame_timer(window, cx);
 3055            }
 3056        }
 3057
 3058        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3059        cx.emit(EditorEvent::SelectionsChanged { local });
 3060
 3061        let selections = &self.selections.disjoint;
 3062        if selections.len() == 1 {
 3063            cx.emit(SearchEvent::ActiveMatchChanged)
 3064        }
 3065        if local {
 3066            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3067                let inmemory_selections = selections
 3068                    .iter()
 3069                    .map(|s| {
 3070                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3071                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3072                    })
 3073                    .collect();
 3074                self.update_restoration_data(cx, |data| {
 3075                    data.selections = inmemory_selections;
 3076                });
 3077
 3078                if WorkspaceSettings::get(None, cx).restore_on_startup
 3079                    != RestoreOnStartupBehavior::None
 3080                {
 3081                    if let Some(workspace_id) =
 3082                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 3083                    {
 3084                        let snapshot = self.buffer().read(cx).snapshot(cx);
 3085                        let selections = selections.clone();
 3086                        let background_executor = cx.background_executor().clone();
 3087                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3088                        self.serialize_selections = cx.background_spawn(async move {
 3089                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3090                            let db_selections = selections
 3091                                .iter()
 3092                                .map(|selection| {
 3093                                    (
 3094                                        selection.start.to_offset(&snapshot),
 3095                                        selection.end.to_offset(&snapshot),
 3096                                    )
 3097                                })
 3098                                .collect();
 3099
 3100                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3101                                .await
 3102                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3103                                .log_err();
 3104                        });
 3105                    }
 3106                }
 3107            }
 3108        }
 3109
 3110        cx.notify();
 3111    }
 3112
 3113    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3114        use text::ToOffset as _;
 3115        use text::ToPoint as _;
 3116
 3117        if self.mode.is_minimap()
 3118            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3119        {
 3120            return;
 3121        }
 3122
 3123        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3124            return;
 3125        };
 3126
 3127        let snapshot = singleton.read(cx).snapshot();
 3128        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3129            let display_snapshot = display_map.snapshot(cx);
 3130
 3131            display_snapshot
 3132                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3133                .map(|fold| {
 3134                    fold.range.start.text_anchor.to_point(&snapshot)
 3135                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3136                })
 3137                .collect()
 3138        });
 3139        self.update_restoration_data(cx, |data| {
 3140            data.folds = inmemory_folds;
 3141        });
 3142
 3143        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3144            return;
 3145        };
 3146        let background_executor = cx.background_executor().clone();
 3147        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3148        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3149            display_map
 3150                .snapshot(cx)
 3151                .folds_in_range(0..snapshot.len())
 3152                .map(|fold| {
 3153                    (
 3154                        fold.range.start.text_anchor.to_offset(&snapshot),
 3155                        fold.range.end.text_anchor.to_offset(&snapshot),
 3156                    )
 3157                })
 3158                .collect()
 3159        });
 3160        self.serialize_folds = cx.background_spawn(async move {
 3161            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3162            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3163                .await
 3164                .with_context(|| {
 3165                    format!(
 3166                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3167                    )
 3168                })
 3169                .log_err();
 3170        });
 3171    }
 3172
 3173    pub fn sync_selections(
 3174        &mut self,
 3175        other: Entity<Editor>,
 3176        cx: &mut Context<Self>,
 3177    ) -> gpui::Subscription {
 3178        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3179        self.selections.change_with(cx, |selections| {
 3180            selections.select_anchors(other_selections);
 3181        });
 3182
 3183        let other_subscription =
 3184            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3185                EditorEvent::SelectionsChanged { local: true } => {
 3186                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3187                    if other_selections.is_empty() {
 3188                        return;
 3189                    }
 3190                    this.selections.change_with(cx, |selections| {
 3191                        selections.select_anchors(other_selections);
 3192                    });
 3193                }
 3194                _ => {}
 3195            });
 3196
 3197        let this_subscription =
 3198            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3199                EditorEvent::SelectionsChanged { local: true } => {
 3200                    let these_selections = this.selections.disjoint.to_vec();
 3201                    if these_selections.is_empty() {
 3202                        return;
 3203                    }
 3204                    other.update(cx, |other_editor, cx| {
 3205                        other_editor.selections.change_with(cx, |selections| {
 3206                            selections.select_anchors(these_selections);
 3207                        })
 3208                    });
 3209                }
 3210                _ => {}
 3211            });
 3212
 3213        Subscription::join(other_subscription, this_subscription)
 3214    }
 3215
 3216    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3217    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3218    /// effects of selection change occur at the end of the transaction.
 3219    pub fn change_selections<R>(
 3220        &mut self,
 3221        effects: SelectionEffects,
 3222        window: &mut Window,
 3223        cx: &mut Context<Self>,
 3224        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3225    ) -> R {
 3226        if let Some(state) = &mut self.deferred_selection_effects_state {
 3227            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3228            state.effects.completions = effects.completions;
 3229            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3230            let (changed, result) = self.selections.change_with(cx, change);
 3231            state.changed |= changed;
 3232            return result;
 3233        }
 3234        let mut state = DeferredSelectionEffectsState {
 3235            changed: false,
 3236            effects,
 3237            old_cursor_position: self.selections.newest_anchor().head(),
 3238            history_entry: SelectionHistoryEntry {
 3239                selections: self.selections.disjoint_anchors(),
 3240                select_next_state: self.select_next_state.clone(),
 3241                select_prev_state: self.select_prev_state.clone(),
 3242                add_selections_state: self.add_selections_state.clone(),
 3243            },
 3244        };
 3245        let (changed, result) = self.selections.change_with(cx, change);
 3246        state.changed = state.changed || changed;
 3247        if self.defer_selection_effects {
 3248            self.deferred_selection_effects_state = Some(state);
 3249        } else {
 3250            self.apply_selection_effects(state, window, cx);
 3251        }
 3252        result
 3253    }
 3254
 3255    /// Defers the effects of selection change, so that the effects of multiple calls to
 3256    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3257    /// to selection history and the state of popovers based on selection position aren't
 3258    /// erroneously updated.
 3259    pub fn with_selection_effects_deferred<R>(
 3260        &mut self,
 3261        window: &mut Window,
 3262        cx: &mut Context<Self>,
 3263        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3264    ) -> R {
 3265        let already_deferred = self.defer_selection_effects;
 3266        self.defer_selection_effects = true;
 3267        let result = update(self, window, cx);
 3268        if !already_deferred {
 3269            self.defer_selection_effects = false;
 3270            if let Some(state) = self.deferred_selection_effects_state.take() {
 3271                self.apply_selection_effects(state, window, cx);
 3272            }
 3273        }
 3274        result
 3275    }
 3276
 3277    fn apply_selection_effects(
 3278        &mut self,
 3279        state: DeferredSelectionEffectsState,
 3280        window: &mut Window,
 3281        cx: &mut Context<Self>,
 3282    ) {
 3283        if state.changed {
 3284            self.selection_history.push(state.history_entry);
 3285
 3286            if let Some(autoscroll) = state.effects.scroll {
 3287                self.request_autoscroll(autoscroll, cx);
 3288            }
 3289
 3290            let old_cursor_position = &state.old_cursor_position;
 3291
 3292            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3293
 3294            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3295                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3296            }
 3297        }
 3298    }
 3299
 3300    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3301    where
 3302        I: IntoIterator<Item = (Range<S>, T)>,
 3303        S: ToOffset,
 3304        T: Into<Arc<str>>,
 3305    {
 3306        if self.read_only(cx) {
 3307            return;
 3308        }
 3309
 3310        self.buffer
 3311            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3312    }
 3313
 3314    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3315    where
 3316        I: IntoIterator<Item = (Range<S>, T)>,
 3317        S: ToOffset,
 3318        T: Into<Arc<str>>,
 3319    {
 3320        if self.read_only(cx) {
 3321            return;
 3322        }
 3323
 3324        self.buffer.update(cx, |buffer, cx| {
 3325            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3326        });
 3327    }
 3328
 3329    pub fn edit_with_block_indent<I, S, T>(
 3330        &mut self,
 3331        edits: I,
 3332        original_indent_columns: Vec<Option<u32>>,
 3333        cx: &mut Context<Self>,
 3334    ) where
 3335        I: IntoIterator<Item = (Range<S>, T)>,
 3336        S: ToOffset,
 3337        T: Into<Arc<str>>,
 3338    {
 3339        if self.read_only(cx) {
 3340            return;
 3341        }
 3342
 3343        self.buffer.update(cx, |buffer, cx| {
 3344            buffer.edit(
 3345                edits,
 3346                Some(AutoindentMode::Block {
 3347                    original_indent_columns,
 3348                }),
 3349                cx,
 3350            )
 3351        });
 3352    }
 3353
 3354    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3355        self.hide_context_menu(window, cx);
 3356
 3357        match phase {
 3358            SelectPhase::Begin {
 3359                position,
 3360                add,
 3361                click_count,
 3362            } => self.begin_selection(position, add, click_count, window, cx),
 3363            SelectPhase::BeginColumnar {
 3364                position,
 3365                goal_column,
 3366                reset,
 3367                mode,
 3368            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3369            SelectPhase::Extend {
 3370                position,
 3371                click_count,
 3372            } => self.extend_selection(position, click_count, window, cx),
 3373            SelectPhase::Update {
 3374                position,
 3375                goal_column,
 3376                scroll_delta,
 3377            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3378            SelectPhase::End => self.end_selection(window, cx),
 3379        }
 3380    }
 3381
 3382    fn extend_selection(
 3383        &mut self,
 3384        position: DisplayPoint,
 3385        click_count: usize,
 3386        window: &mut Window,
 3387        cx: &mut Context<Self>,
 3388    ) {
 3389        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3390        let tail = self.selections.newest::<usize>(cx).tail();
 3391        self.begin_selection(position, false, click_count, window, cx);
 3392
 3393        let position = position.to_offset(&display_map, Bias::Left);
 3394        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3395
 3396        let mut pending_selection = self
 3397            .selections
 3398            .pending_anchor()
 3399            .expect("extend_selection not called with pending selection");
 3400        if position >= tail {
 3401            pending_selection.start = tail_anchor;
 3402        } else {
 3403            pending_selection.end = tail_anchor;
 3404            pending_selection.reversed = true;
 3405        }
 3406
 3407        let mut pending_mode = self.selections.pending_mode().unwrap();
 3408        match &mut pending_mode {
 3409            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3410            _ => {}
 3411        }
 3412
 3413        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3414            SelectionEffects::scroll(Autoscroll::fit())
 3415        } else {
 3416            SelectionEffects::no_scroll()
 3417        };
 3418
 3419        self.change_selections(effects, window, cx, |s| {
 3420            s.set_pending(pending_selection, pending_mode)
 3421        });
 3422    }
 3423
 3424    fn begin_selection(
 3425        &mut self,
 3426        position: DisplayPoint,
 3427        add: bool,
 3428        click_count: usize,
 3429        window: &mut Window,
 3430        cx: &mut Context<Self>,
 3431    ) {
 3432        if !self.focus_handle.is_focused(window) {
 3433            self.last_focused_descendant = None;
 3434            window.focus(&self.focus_handle);
 3435        }
 3436
 3437        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3438        let buffer = &display_map.buffer_snapshot;
 3439        let position = display_map.clip_point(position, Bias::Left);
 3440
 3441        let start;
 3442        let end;
 3443        let mode;
 3444        let mut auto_scroll;
 3445        match click_count {
 3446            1 => {
 3447                start = buffer.anchor_before(position.to_point(&display_map));
 3448                end = start;
 3449                mode = SelectMode::Character;
 3450                auto_scroll = true;
 3451            }
 3452            2 => {
 3453                let position = display_map
 3454                    .clip_point(position, Bias::Left)
 3455                    .to_offset(&display_map, Bias::Left);
 3456                let (range, _) = buffer.surrounding_word(position, false);
 3457                start = buffer.anchor_before(range.start);
 3458                end = buffer.anchor_before(range.end);
 3459                mode = SelectMode::Word(start..end);
 3460                auto_scroll = true;
 3461            }
 3462            3 => {
 3463                let position = display_map
 3464                    .clip_point(position, Bias::Left)
 3465                    .to_point(&display_map);
 3466                let line_start = display_map.prev_line_boundary(position).0;
 3467                let next_line_start = buffer.clip_point(
 3468                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3469                    Bias::Left,
 3470                );
 3471                start = buffer.anchor_before(line_start);
 3472                end = buffer.anchor_before(next_line_start);
 3473                mode = SelectMode::Line(start..end);
 3474                auto_scroll = true;
 3475            }
 3476            _ => {
 3477                start = buffer.anchor_before(0);
 3478                end = buffer.anchor_before(buffer.len());
 3479                mode = SelectMode::All;
 3480                auto_scroll = false;
 3481            }
 3482        }
 3483        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3484
 3485        let point_to_delete: Option<usize> = {
 3486            let selected_points: Vec<Selection<Point>> =
 3487                self.selections.disjoint_in_range(start..end, cx);
 3488
 3489            if !add || click_count > 1 {
 3490                None
 3491            } else if !selected_points.is_empty() {
 3492                Some(selected_points[0].id)
 3493            } else {
 3494                let clicked_point_already_selected =
 3495                    self.selections.disjoint.iter().find(|selection| {
 3496                        selection.start.to_point(buffer) == start.to_point(buffer)
 3497                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3498                    });
 3499
 3500                clicked_point_already_selected.map(|selection| selection.id)
 3501            }
 3502        };
 3503
 3504        let selections_count = self.selections.count();
 3505        let effects = if auto_scroll {
 3506            SelectionEffects::default()
 3507        } else {
 3508            SelectionEffects::no_scroll()
 3509        };
 3510
 3511        self.change_selections(effects, window, cx, |s| {
 3512            if let Some(point_to_delete) = point_to_delete {
 3513                s.delete(point_to_delete);
 3514
 3515                if selections_count == 1 {
 3516                    s.set_pending_anchor_range(start..end, mode);
 3517                }
 3518            } else {
 3519                if !add {
 3520                    s.clear_disjoint();
 3521                }
 3522
 3523                s.set_pending_anchor_range(start..end, mode);
 3524            }
 3525        });
 3526    }
 3527
 3528    fn begin_columnar_selection(
 3529        &mut self,
 3530        position: DisplayPoint,
 3531        goal_column: u32,
 3532        reset: bool,
 3533        mode: ColumnarMode,
 3534        window: &mut Window,
 3535        cx: &mut Context<Self>,
 3536    ) {
 3537        if !self.focus_handle.is_focused(window) {
 3538            self.last_focused_descendant = None;
 3539            window.focus(&self.focus_handle);
 3540        }
 3541
 3542        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3543
 3544        if reset {
 3545            let pointer_position = display_map
 3546                .buffer_snapshot
 3547                .anchor_before(position.to_point(&display_map));
 3548
 3549            self.change_selections(
 3550                SelectionEffects::scroll(Autoscroll::newest()),
 3551                window,
 3552                cx,
 3553                |s| {
 3554                    s.clear_disjoint();
 3555                    s.set_pending_anchor_range(
 3556                        pointer_position..pointer_position,
 3557                        SelectMode::Character,
 3558                    );
 3559                },
 3560            );
 3561        };
 3562
 3563        let tail = self.selections.newest::<Point>(cx).tail();
 3564        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3565        self.columnar_selection_state = match mode {
 3566            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3567                selection_tail: selection_anchor,
 3568                display_point: if reset {
 3569                    if position.column() != goal_column {
 3570                        Some(DisplayPoint::new(position.row(), goal_column))
 3571                    } else {
 3572                        None
 3573                    }
 3574                } else {
 3575                    None
 3576                },
 3577            }),
 3578            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3579                selection_tail: selection_anchor,
 3580            }),
 3581        };
 3582
 3583        if !reset {
 3584            self.select_columns(position, goal_column, &display_map, window, cx);
 3585        }
 3586    }
 3587
 3588    fn update_selection(
 3589        &mut self,
 3590        position: DisplayPoint,
 3591        goal_column: u32,
 3592        scroll_delta: gpui::Point<f32>,
 3593        window: &mut Window,
 3594        cx: &mut Context<Self>,
 3595    ) {
 3596        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3597
 3598        if self.columnar_selection_state.is_some() {
 3599            self.select_columns(position, goal_column, &display_map, window, cx);
 3600        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3601            let buffer = &display_map.buffer_snapshot;
 3602            let head;
 3603            let tail;
 3604            let mode = self.selections.pending_mode().unwrap();
 3605            match &mode {
 3606                SelectMode::Character => {
 3607                    head = position.to_point(&display_map);
 3608                    tail = pending.tail().to_point(buffer);
 3609                }
 3610                SelectMode::Word(original_range) => {
 3611                    let offset = display_map
 3612                        .clip_point(position, Bias::Left)
 3613                        .to_offset(&display_map, Bias::Left);
 3614                    let original_range = original_range.to_offset(buffer);
 3615
 3616                    let head_offset = if buffer.is_inside_word(offset, false)
 3617                        || original_range.contains(&offset)
 3618                    {
 3619                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3620                        if word_range.start < original_range.start {
 3621                            word_range.start
 3622                        } else {
 3623                            word_range.end
 3624                        }
 3625                    } else {
 3626                        offset
 3627                    };
 3628
 3629                    head = head_offset.to_point(buffer);
 3630                    if head_offset <= original_range.start {
 3631                        tail = original_range.end.to_point(buffer);
 3632                    } else {
 3633                        tail = original_range.start.to_point(buffer);
 3634                    }
 3635                }
 3636                SelectMode::Line(original_range) => {
 3637                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3638
 3639                    let position = display_map
 3640                        .clip_point(position, Bias::Left)
 3641                        .to_point(&display_map);
 3642                    let line_start = display_map.prev_line_boundary(position).0;
 3643                    let next_line_start = buffer.clip_point(
 3644                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3645                        Bias::Left,
 3646                    );
 3647
 3648                    if line_start < original_range.start {
 3649                        head = line_start
 3650                    } else {
 3651                        head = next_line_start
 3652                    }
 3653
 3654                    if head <= original_range.start {
 3655                        tail = original_range.end;
 3656                    } else {
 3657                        tail = original_range.start;
 3658                    }
 3659                }
 3660                SelectMode::All => {
 3661                    return;
 3662                }
 3663            };
 3664
 3665            if head < tail {
 3666                pending.start = buffer.anchor_before(head);
 3667                pending.end = buffer.anchor_before(tail);
 3668                pending.reversed = true;
 3669            } else {
 3670                pending.start = buffer.anchor_before(tail);
 3671                pending.end = buffer.anchor_before(head);
 3672                pending.reversed = false;
 3673            }
 3674
 3675            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3676                s.set_pending(pending, mode);
 3677            });
 3678        } else {
 3679            log::error!("update_selection dispatched with no pending selection");
 3680            return;
 3681        }
 3682
 3683        self.apply_scroll_delta(scroll_delta, window, cx);
 3684        cx.notify();
 3685    }
 3686
 3687    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3688        self.columnar_selection_state.take();
 3689        if self.selections.pending_anchor().is_some() {
 3690            let selections = self.selections.all::<usize>(cx);
 3691            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3692                s.select(selections);
 3693                s.clear_pending();
 3694            });
 3695        }
 3696    }
 3697
 3698    fn select_columns(
 3699        &mut self,
 3700        head: DisplayPoint,
 3701        goal_column: u32,
 3702        display_map: &DisplaySnapshot,
 3703        window: &mut Window,
 3704        cx: &mut Context<Self>,
 3705    ) {
 3706        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3707            return;
 3708        };
 3709
 3710        let tail = match columnar_state {
 3711            ColumnarSelectionState::FromMouse {
 3712                selection_tail,
 3713                display_point,
 3714            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(&display_map)),
 3715            ColumnarSelectionState::FromSelection { selection_tail } => {
 3716                selection_tail.to_display_point(&display_map)
 3717            }
 3718        };
 3719
 3720        let start_row = cmp::min(tail.row(), head.row());
 3721        let end_row = cmp::max(tail.row(), head.row());
 3722        let start_column = cmp::min(tail.column(), goal_column);
 3723        let end_column = cmp::max(tail.column(), goal_column);
 3724        let reversed = start_column < tail.column();
 3725
 3726        let selection_ranges = (start_row.0..=end_row.0)
 3727            .map(DisplayRow)
 3728            .filter_map(|row| {
 3729                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3730                    || start_column <= display_map.line_len(row))
 3731                    && !display_map.is_block_line(row)
 3732                {
 3733                    let start = display_map
 3734                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3735                        .to_point(display_map);
 3736                    let end = display_map
 3737                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3738                        .to_point(display_map);
 3739                    if reversed {
 3740                        Some(end..start)
 3741                    } else {
 3742                        Some(start..end)
 3743                    }
 3744                } else {
 3745                    None
 3746                }
 3747            })
 3748            .collect::<Vec<_>>();
 3749
 3750        let ranges = match columnar_state {
 3751            ColumnarSelectionState::FromMouse { .. } => {
 3752                let mut non_empty_ranges = selection_ranges
 3753                    .iter()
 3754                    .filter(|selection_range| selection_range.start != selection_range.end)
 3755                    .peekable();
 3756                if non_empty_ranges.peek().is_some() {
 3757                    non_empty_ranges.cloned().collect()
 3758                } else {
 3759                    selection_ranges
 3760                }
 3761            }
 3762            _ => selection_ranges,
 3763        };
 3764
 3765        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3766            s.select_ranges(ranges);
 3767        });
 3768        cx.notify();
 3769    }
 3770
 3771    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3772        self.selections
 3773            .all_adjusted(cx)
 3774            .iter()
 3775            .any(|selection| !selection.is_empty())
 3776    }
 3777
 3778    pub fn has_pending_nonempty_selection(&self) -> bool {
 3779        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3780            Some(Selection { start, end, .. }) => start != end,
 3781            None => false,
 3782        };
 3783
 3784        pending_nonempty_selection
 3785            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3786    }
 3787
 3788    pub fn has_pending_selection(&self) -> bool {
 3789        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3790    }
 3791
 3792    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3793        self.selection_mark_mode = false;
 3794        self.selection_drag_state = SelectionDragState::None;
 3795
 3796        if self.clear_expanded_diff_hunks(cx) {
 3797            cx.notify();
 3798            return;
 3799        }
 3800        if self.dismiss_menus_and_popups(true, window, cx) {
 3801            return;
 3802        }
 3803
 3804        if self.mode.is_full()
 3805            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3806        {
 3807            return;
 3808        }
 3809
 3810        cx.propagate();
 3811    }
 3812
 3813    pub fn dismiss_menus_and_popups(
 3814        &mut self,
 3815        is_user_requested: bool,
 3816        window: &mut Window,
 3817        cx: &mut Context<Self>,
 3818    ) -> bool {
 3819        if self.take_rename(false, window, cx).is_some() {
 3820            return true;
 3821        }
 3822
 3823        if hide_hover(self, cx) {
 3824            return true;
 3825        }
 3826
 3827        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3828            return true;
 3829        }
 3830
 3831        if self.hide_context_menu(window, cx).is_some() {
 3832            return true;
 3833        }
 3834
 3835        if self.mouse_context_menu.take().is_some() {
 3836            return true;
 3837        }
 3838
 3839        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3840            return true;
 3841        }
 3842
 3843        if self.snippet_stack.pop().is_some() {
 3844            return true;
 3845        }
 3846
 3847        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3848            self.dismiss_diagnostics(cx);
 3849            return true;
 3850        }
 3851
 3852        false
 3853    }
 3854
 3855    fn linked_editing_ranges_for(
 3856        &self,
 3857        selection: Range<text::Anchor>,
 3858        cx: &App,
 3859    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3860        if self.linked_edit_ranges.is_empty() {
 3861            return None;
 3862        }
 3863        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3864            selection.end.buffer_id.and_then(|end_buffer_id| {
 3865                if selection.start.buffer_id != Some(end_buffer_id) {
 3866                    return None;
 3867                }
 3868                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3869                let snapshot = buffer.read(cx).snapshot();
 3870                self.linked_edit_ranges
 3871                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3872                    .map(|ranges| (ranges, snapshot, buffer))
 3873            })?;
 3874        use text::ToOffset as TO;
 3875        // find offset from the start of current range to current cursor position
 3876        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3877
 3878        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3879        let start_difference = start_offset - start_byte_offset;
 3880        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3881        let end_difference = end_offset - start_byte_offset;
 3882        // Current range has associated linked ranges.
 3883        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3884        for range in linked_ranges.iter() {
 3885            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3886            let end_offset = start_offset + end_difference;
 3887            let start_offset = start_offset + start_difference;
 3888            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3889                continue;
 3890            }
 3891            if self.selections.disjoint_anchor_ranges().any(|s| {
 3892                if s.start.buffer_id != selection.start.buffer_id
 3893                    || s.end.buffer_id != selection.end.buffer_id
 3894                {
 3895                    return false;
 3896                }
 3897                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3898                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3899            }) {
 3900                continue;
 3901            }
 3902            let start = buffer_snapshot.anchor_after(start_offset);
 3903            let end = buffer_snapshot.anchor_after(end_offset);
 3904            linked_edits
 3905                .entry(buffer.clone())
 3906                .or_default()
 3907                .push(start..end);
 3908        }
 3909        Some(linked_edits)
 3910    }
 3911
 3912    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3913        let text: Arc<str> = text.into();
 3914
 3915        if self.read_only(cx) {
 3916            return;
 3917        }
 3918
 3919        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3920
 3921        let selections = self.selections.all_adjusted(cx);
 3922        let mut bracket_inserted = false;
 3923        let mut edits = Vec::new();
 3924        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3925        let mut new_selections = Vec::with_capacity(selections.len());
 3926        let mut new_autoclose_regions = Vec::new();
 3927        let snapshot = self.buffer.read(cx).read(cx);
 3928        let mut clear_linked_edit_ranges = false;
 3929
 3930        for (selection, autoclose_region) in
 3931            self.selections_with_autoclose_regions(selections, &snapshot)
 3932        {
 3933            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3934                // Determine if the inserted text matches the opening or closing
 3935                // bracket of any of this language's bracket pairs.
 3936                let mut bracket_pair = None;
 3937                let mut is_bracket_pair_start = false;
 3938                let mut is_bracket_pair_end = false;
 3939                if !text.is_empty() {
 3940                    let mut bracket_pair_matching_end = None;
 3941                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3942                    //  and they are removing the character that triggered IME popup.
 3943                    for (pair, enabled) in scope.brackets() {
 3944                        if !pair.close && !pair.surround {
 3945                            continue;
 3946                        }
 3947
 3948                        if enabled && pair.start.ends_with(text.as_ref()) {
 3949                            let prefix_len = pair.start.len() - text.len();
 3950                            let preceding_text_matches_prefix = prefix_len == 0
 3951                                || (selection.start.column >= (prefix_len as u32)
 3952                                    && snapshot.contains_str_at(
 3953                                        Point::new(
 3954                                            selection.start.row,
 3955                                            selection.start.column - (prefix_len as u32),
 3956                                        ),
 3957                                        &pair.start[..prefix_len],
 3958                                    ));
 3959                            if preceding_text_matches_prefix {
 3960                                bracket_pair = Some(pair.clone());
 3961                                is_bracket_pair_start = true;
 3962                                break;
 3963                            }
 3964                        }
 3965                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3966                        {
 3967                            // take first bracket pair matching end, but don't break in case a later bracket
 3968                            // pair matches start
 3969                            bracket_pair_matching_end = Some(pair.clone());
 3970                        }
 3971                    }
 3972                    if let Some(end) = bracket_pair_matching_end
 3973                        && bracket_pair.is_none()
 3974                    {
 3975                        bracket_pair = Some(end);
 3976                        is_bracket_pair_end = true;
 3977                    }
 3978                }
 3979
 3980                if let Some(bracket_pair) = bracket_pair {
 3981                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3982                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3983                    let auto_surround =
 3984                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3985                    if selection.is_empty() {
 3986                        if is_bracket_pair_start {
 3987                            // If the inserted text is a suffix of an opening bracket and the
 3988                            // selection is preceded by the rest of the opening bracket, then
 3989                            // insert the closing bracket.
 3990                            let following_text_allows_autoclose = snapshot
 3991                                .chars_at(selection.start)
 3992                                .next()
 3993                                .map_or(true, |c| scope.should_autoclose_before(c));
 3994
 3995                            let preceding_text_allows_autoclose = selection.start.column == 0
 3996                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3997                                    true,
 3998                                    |c| {
 3999                                        bracket_pair.start != bracket_pair.end
 4000                                            || !snapshot
 4001                                                .char_classifier_at(selection.start)
 4002                                                .is_word(c)
 4003                                    },
 4004                                );
 4005
 4006                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4007                                && bracket_pair.start.len() == 1
 4008                            {
 4009                                let target = bracket_pair.start.chars().next().unwrap();
 4010                                let current_line_count = snapshot
 4011                                    .reversed_chars_at(selection.start)
 4012                                    .take_while(|&c| c != '\n')
 4013                                    .filter(|&c| c == target)
 4014                                    .count();
 4015                                current_line_count % 2 == 1
 4016                            } else {
 4017                                false
 4018                            };
 4019
 4020                            if autoclose
 4021                                && bracket_pair.close
 4022                                && following_text_allows_autoclose
 4023                                && preceding_text_allows_autoclose
 4024                                && !is_closing_quote
 4025                            {
 4026                                let anchor = snapshot.anchor_before(selection.end);
 4027                                new_selections.push((selection.map(|_| anchor), text.len()));
 4028                                new_autoclose_regions.push((
 4029                                    anchor,
 4030                                    text.len(),
 4031                                    selection.id,
 4032                                    bracket_pair.clone(),
 4033                                ));
 4034                                edits.push((
 4035                                    selection.range(),
 4036                                    format!("{}{}", text, bracket_pair.end).into(),
 4037                                ));
 4038                                bracket_inserted = true;
 4039                                continue;
 4040                            }
 4041                        }
 4042
 4043                        if let Some(region) = autoclose_region {
 4044                            // If the selection is followed by an auto-inserted closing bracket,
 4045                            // then don't insert that closing bracket again; just move the selection
 4046                            // past the closing bracket.
 4047                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4048                                && text.as_ref() == region.pair.end.as_str()
 4049                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4050                            if should_skip {
 4051                                let anchor = snapshot.anchor_after(selection.end);
 4052                                new_selections
 4053                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4054                                continue;
 4055                            }
 4056                        }
 4057
 4058                        let always_treat_brackets_as_autoclosed = snapshot
 4059                            .language_settings_at(selection.start, cx)
 4060                            .always_treat_brackets_as_autoclosed;
 4061                        if always_treat_brackets_as_autoclosed
 4062                            && is_bracket_pair_end
 4063                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4064                        {
 4065                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4066                            // and the inserted text is a closing bracket and the selection is followed
 4067                            // by the closing bracket then move the selection past the closing bracket.
 4068                            let anchor = snapshot.anchor_after(selection.end);
 4069                            new_selections.push((selection.map(|_| anchor), text.len()));
 4070                            continue;
 4071                        }
 4072                    }
 4073                    // If an opening bracket is 1 character long and is typed while
 4074                    // text is selected, then surround that text with the bracket pair.
 4075                    else if auto_surround
 4076                        && bracket_pair.surround
 4077                        && is_bracket_pair_start
 4078                        && bracket_pair.start.chars().count() == 1
 4079                    {
 4080                        edits.push((selection.start..selection.start, text.clone()));
 4081                        edits.push((
 4082                            selection.end..selection.end,
 4083                            bracket_pair.end.as_str().into(),
 4084                        ));
 4085                        bracket_inserted = true;
 4086                        new_selections.push((
 4087                            Selection {
 4088                                id: selection.id,
 4089                                start: snapshot.anchor_after(selection.start),
 4090                                end: snapshot.anchor_before(selection.end),
 4091                                reversed: selection.reversed,
 4092                                goal: selection.goal,
 4093                            },
 4094                            0,
 4095                        ));
 4096                        continue;
 4097                    }
 4098                }
 4099            }
 4100
 4101            if self.auto_replace_emoji_shortcode
 4102                && selection.is_empty()
 4103                && text.as_ref().ends_with(':')
 4104            {
 4105                if let Some(possible_emoji_short_code) =
 4106                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4107                {
 4108                    if !possible_emoji_short_code.is_empty() {
 4109                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 4110                            let emoji_shortcode_start = Point::new(
 4111                                selection.start.row,
 4112                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4113                            );
 4114
 4115                            // Remove shortcode from buffer
 4116                            edits.push((
 4117                                emoji_shortcode_start..selection.start,
 4118                                "".to_string().into(),
 4119                            ));
 4120                            new_selections.push((
 4121                                Selection {
 4122                                    id: selection.id,
 4123                                    start: snapshot.anchor_after(emoji_shortcode_start),
 4124                                    end: snapshot.anchor_before(selection.start),
 4125                                    reversed: selection.reversed,
 4126                                    goal: selection.goal,
 4127                                },
 4128                                0,
 4129                            ));
 4130
 4131                            // Insert emoji
 4132                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 4133                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4134                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 4135
 4136                            continue;
 4137                        }
 4138                    }
 4139                }
 4140            }
 4141
 4142            // If not handling any auto-close operation, then just replace the selected
 4143            // text with the given input and move the selection to the end of the
 4144            // newly inserted text.
 4145            let anchor = snapshot.anchor_after(selection.end);
 4146            if !self.linked_edit_ranges.is_empty() {
 4147                let start_anchor = snapshot.anchor_before(selection.start);
 4148
 4149                let is_word_char = text.chars().next().map_or(true, |char| {
 4150                    let classifier = snapshot
 4151                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4152                        .ignore_punctuation(true);
 4153                    classifier.is_word(char)
 4154                });
 4155
 4156                if is_word_char {
 4157                    if let Some(ranges) = self
 4158                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4159                    {
 4160                        for (buffer, edits) in ranges {
 4161                            linked_edits
 4162                                .entry(buffer.clone())
 4163                                .or_default()
 4164                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4165                        }
 4166                    }
 4167                } else {
 4168                    clear_linked_edit_ranges = true;
 4169                }
 4170            }
 4171
 4172            new_selections.push((selection.map(|_| anchor), 0));
 4173            edits.push((selection.start..selection.end, text.clone()));
 4174        }
 4175
 4176        drop(snapshot);
 4177
 4178        self.transact(window, cx, |this, window, cx| {
 4179            if clear_linked_edit_ranges {
 4180                this.linked_edit_ranges.clear();
 4181            }
 4182            let initial_buffer_versions =
 4183                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4184
 4185            this.buffer.update(cx, |buffer, cx| {
 4186                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4187            });
 4188            for (buffer, edits) in linked_edits {
 4189                buffer.update(cx, |buffer, cx| {
 4190                    let snapshot = buffer.snapshot();
 4191                    let edits = edits
 4192                        .into_iter()
 4193                        .map(|(range, text)| {
 4194                            use text::ToPoint as TP;
 4195                            let end_point = TP::to_point(&range.end, &snapshot);
 4196                            let start_point = TP::to_point(&range.start, &snapshot);
 4197                            (start_point..end_point, text)
 4198                        })
 4199                        .sorted_by_key(|(range, _)| range.start);
 4200                    buffer.edit(edits, None, cx);
 4201                })
 4202            }
 4203            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4204            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4205            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4206            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4207                .zip(new_selection_deltas)
 4208                .map(|(selection, delta)| Selection {
 4209                    id: selection.id,
 4210                    start: selection.start + delta,
 4211                    end: selection.end + delta,
 4212                    reversed: selection.reversed,
 4213                    goal: SelectionGoal::None,
 4214                })
 4215                .collect::<Vec<_>>();
 4216
 4217            let mut i = 0;
 4218            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4219                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4220                let start = map.buffer_snapshot.anchor_before(position);
 4221                let end = map.buffer_snapshot.anchor_after(position);
 4222                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4223                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4224                        Ordering::Less => i += 1,
 4225                        Ordering::Greater => break,
 4226                        Ordering::Equal => {
 4227                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4228                                Ordering::Less => i += 1,
 4229                                Ordering::Equal => break,
 4230                                Ordering::Greater => break,
 4231                            }
 4232                        }
 4233                    }
 4234                }
 4235                this.autoclose_regions.insert(
 4236                    i,
 4237                    AutocloseRegion {
 4238                        selection_id,
 4239                        range: start..end,
 4240                        pair,
 4241                    },
 4242                );
 4243            }
 4244
 4245            let had_active_edit_prediction = this.has_active_edit_prediction();
 4246            this.change_selections(
 4247                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4248                window,
 4249                cx,
 4250                |s| s.select(new_selections),
 4251            );
 4252
 4253            if !bracket_inserted {
 4254                if let Some(on_type_format_task) =
 4255                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4256                {
 4257                    on_type_format_task.detach_and_log_err(cx);
 4258                }
 4259            }
 4260
 4261            let editor_settings = EditorSettings::get_global(cx);
 4262            if bracket_inserted
 4263                && (editor_settings.auto_signature_help
 4264                    || editor_settings.show_signature_help_after_edits)
 4265            {
 4266                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4267            }
 4268
 4269            let trigger_in_words =
 4270                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4271            if this.hard_wrap.is_some() {
 4272                let latest: Range<Point> = this.selections.newest(cx).range();
 4273                if latest.is_empty()
 4274                    && this
 4275                        .buffer()
 4276                        .read(cx)
 4277                        .snapshot(cx)
 4278                        .line_len(MultiBufferRow(latest.start.row))
 4279                        == latest.start.column
 4280                {
 4281                    this.rewrap_impl(
 4282                        RewrapOptions {
 4283                            override_language_settings: true,
 4284                            preserve_existing_whitespace: true,
 4285                        },
 4286                        cx,
 4287                    )
 4288                }
 4289            }
 4290            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4291            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4292            this.refresh_edit_prediction(true, false, window, cx);
 4293            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4294        });
 4295    }
 4296
 4297    fn find_possible_emoji_shortcode_at_position(
 4298        snapshot: &MultiBufferSnapshot,
 4299        position: Point,
 4300    ) -> Option<String> {
 4301        let mut chars = Vec::new();
 4302        let mut found_colon = false;
 4303        for char in snapshot.reversed_chars_at(position).take(100) {
 4304            // Found a possible emoji shortcode in the middle of the buffer
 4305            if found_colon {
 4306                if char.is_whitespace() {
 4307                    chars.reverse();
 4308                    return Some(chars.iter().collect());
 4309                }
 4310                // If the previous character is not a whitespace, we are in the middle of a word
 4311                // and we only want to complete the shortcode if the word is made up of other emojis
 4312                let mut containing_word = String::new();
 4313                for ch in snapshot
 4314                    .reversed_chars_at(position)
 4315                    .skip(chars.len() + 1)
 4316                    .take(100)
 4317                {
 4318                    if ch.is_whitespace() {
 4319                        break;
 4320                    }
 4321                    containing_word.push(ch);
 4322                }
 4323                let containing_word = containing_word.chars().rev().collect::<String>();
 4324                if util::word_consists_of_emojis(containing_word.as_str()) {
 4325                    chars.reverse();
 4326                    return Some(chars.iter().collect());
 4327                }
 4328            }
 4329
 4330            if char.is_whitespace() || !char.is_ascii() {
 4331                return None;
 4332            }
 4333            if char == ':' {
 4334                found_colon = true;
 4335            } else {
 4336                chars.push(char);
 4337            }
 4338        }
 4339        // Found a possible emoji shortcode at the beginning of the buffer
 4340        chars.reverse();
 4341        Some(chars.iter().collect())
 4342    }
 4343
 4344    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4345        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4346        self.transact(window, cx, |this, window, cx| {
 4347            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4348                let selections = this.selections.all::<usize>(cx);
 4349                let multi_buffer = this.buffer.read(cx);
 4350                let buffer = multi_buffer.snapshot(cx);
 4351                selections
 4352                    .iter()
 4353                    .map(|selection| {
 4354                        let start_point = selection.start.to_point(&buffer);
 4355                        let mut existing_indent =
 4356                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4357                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4358                        let start = selection.start;
 4359                        let end = selection.end;
 4360                        let selection_is_empty = start == end;
 4361                        let language_scope = buffer.language_scope_at(start);
 4362                        let (
 4363                            comment_delimiter,
 4364                            doc_delimiter,
 4365                            insert_extra_newline,
 4366                            indent_on_newline,
 4367                            indent_on_extra_newline,
 4368                        ) = if let Some(language) = &language_scope {
 4369                            let mut insert_extra_newline =
 4370                                insert_extra_newline_brackets(&buffer, start..end, language)
 4371                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4372
 4373                            // Comment extension on newline is allowed only for cursor selections
 4374                            let comment_delimiter = maybe!({
 4375                                if !selection_is_empty {
 4376                                    return None;
 4377                                }
 4378
 4379                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4380                                    return None;
 4381                                }
 4382
 4383                                let delimiters = language.line_comment_prefixes();
 4384                                let max_len_of_delimiter =
 4385                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4386                                let (snapshot, range) =
 4387                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4388
 4389                                let num_of_whitespaces = snapshot
 4390                                    .chars_for_range(range.clone())
 4391                                    .take_while(|c| c.is_whitespace())
 4392                                    .count();
 4393                                let comment_candidate = snapshot
 4394                                    .chars_for_range(range.clone())
 4395                                    .skip(num_of_whitespaces)
 4396                                    .take(max_len_of_delimiter)
 4397                                    .collect::<String>();
 4398                                let (delimiter, trimmed_len) = delimiters
 4399                                    .iter()
 4400                                    .filter_map(|delimiter| {
 4401                                        let prefix = delimiter.trim_end();
 4402                                        if comment_candidate.starts_with(prefix) {
 4403                                            Some((delimiter, prefix.len()))
 4404                                        } else {
 4405                                            None
 4406                                        }
 4407                                    })
 4408                                    .max_by_key(|(_, len)| *len)?;
 4409
 4410                                if let Some(BlockCommentConfig {
 4411                                    start: block_start, ..
 4412                                }) = language.block_comment()
 4413                                {
 4414                                    let block_start_trimmed = block_start.trim_end();
 4415                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4416                                        let line_content = snapshot
 4417                                            .chars_for_range(range)
 4418                                            .skip(num_of_whitespaces)
 4419                                            .take(block_start_trimmed.len())
 4420                                            .collect::<String>();
 4421
 4422                                        if line_content.starts_with(block_start_trimmed) {
 4423                                            return None;
 4424                                        }
 4425                                    }
 4426                                }
 4427
 4428                                let cursor_is_placed_after_comment_marker =
 4429                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4430                                if cursor_is_placed_after_comment_marker {
 4431                                    Some(delimiter.clone())
 4432                                } else {
 4433                                    None
 4434                                }
 4435                            });
 4436
 4437                            let mut indent_on_newline = IndentSize::spaces(0);
 4438                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4439
 4440                            let doc_delimiter = maybe!({
 4441                                if !selection_is_empty {
 4442                                    return None;
 4443                                }
 4444
 4445                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4446                                    return None;
 4447                                }
 4448
 4449                                let BlockCommentConfig {
 4450                                    start: start_tag,
 4451                                    end: end_tag,
 4452                                    prefix: delimiter,
 4453                                    tab_size: len,
 4454                                } = language.documentation_comment()?;
 4455                                let is_within_block_comment = buffer
 4456                                    .language_scope_at(start_point)
 4457                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4458                                if !is_within_block_comment {
 4459                                    return None;
 4460                                }
 4461
 4462                                let (snapshot, range) =
 4463                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4464
 4465                                let num_of_whitespaces = snapshot
 4466                                    .chars_for_range(range.clone())
 4467                                    .take_while(|c| c.is_whitespace())
 4468                                    .count();
 4469
 4470                                // 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.
 4471                                let column = start_point.column;
 4472                                let cursor_is_after_start_tag = {
 4473                                    let start_tag_len = start_tag.len();
 4474                                    let start_tag_line = snapshot
 4475                                        .chars_for_range(range.clone())
 4476                                        .skip(num_of_whitespaces)
 4477                                        .take(start_tag_len)
 4478                                        .collect::<String>();
 4479                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4480                                        num_of_whitespaces + start_tag_len <= column as usize
 4481                                    } else {
 4482                                        false
 4483                                    }
 4484                                };
 4485
 4486                                let cursor_is_after_delimiter = {
 4487                                    let delimiter_trim = delimiter.trim_end();
 4488                                    let delimiter_line = snapshot
 4489                                        .chars_for_range(range.clone())
 4490                                        .skip(num_of_whitespaces)
 4491                                        .take(delimiter_trim.len())
 4492                                        .collect::<String>();
 4493                                    if delimiter_line.starts_with(delimiter_trim) {
 4494                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4495                                    } else {
 4496                                        false
 4497                                    }
 4498                                };
 4499
 4500                                let cursor_is_before_end_tag_if_exists = {
 4501                                    let mut char_position = 0u32;
 4502                                    let mut end_tag_offset = None;
 4503
 4504                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4505                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4506                                            let chars_before_match =
 4507                                                chunk[..byte_pos].chars().count() as u32;
 4508                                            end_tag_offset =
 4509                                                Some(char_position + chars_before_match);
 4510                                            break 'outer;
 4511                                        }
 4512                                        char_position += chunk.chars().count() as u32;
 4513                                    }
 4514
 4515                                    if let Some(end_tag_offset) = end_tag_offset {
 4516                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4517                                        if cursor_is_after_start_tag {
 4518                                            if cursor_is_before_end_tag {
 4519                                                insert_extra_newline = true;
 4520                                            }
 4521                                            let cursor_is_at_start_of_end_tag =
 4522                                                column == end_tag_offset;
 4523                                            if cursor_is_at_start_of_end_tag {
 4524                                                indent_on_extra_newline.len = *len;
 4525                                            }
 4526                                        }
 4527                                        cursor_is_before_end_tag
 4528                                    } else {
 4529                                        true
 4530                                    }
 4531                                };
 4532
 4533                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4534                                    && cursor_is_before_end_tag_if_exists
 4535                                {
 4536                                    if cursor_is_after_start_tag {
 4537                                        indent_on_newline.len = *len;
 4538                                    }
 4539                                    Some(delimiter.clone())
 4540                                } else {
 4541                                    None
 4542                                }
 4543                            });
 4544
 4545                            (
 4546                                comment_delimiter,
 4547                                doc_delimiter,
 4548                                insert_extra_newline,
 4549                                indent_on_newline,
 4550                                indent_on_extra_newline,
 4551                            )
 4552                        } else {
 4553                            (
 4554                                None,
 4555                                None,
 4556                                false,
 4557                                IndentSize::default(),
 4558                                IndentSize::default(),
 4559                            )
 4560                        };
 4561
 4562                        let prevent_auto_indent = doc_delimiter.is_some();
 4563                        let delimiter = comment_delimiter.or(doc_delimiter);
 4564
 4565                        let capacity_for_delimiter =
 4566                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4567                        let mut new_text = String::with_capacity(
 4568                            1 + capacity_for_delimiter
 4569                                + existing_indent.len as usize
 4570                                + indent_on_newline.len as usize
 4571                                + indent_on_extra_newline.len as usize,
 4572                        );
 4573                        new_text.push('\n');
 4574                        new_text.extend(existing_indent.chars());
 4575                        new_text.extend(indent_on_newline.chars());
 4576
 4577                        if let Some(delimiter) = &delimiter {
 4578                            new_text.push_str(delimiter);
 4579                        }
 4580
 4581                        if insert_extra_newline {
 4582                            new_text.push('\n');
 4583                            new_text.extend(existing_indent.chars());
 4584                            new_text.extend(indent_on_extra_newline.chars());
 4585                        }
 4586
 4587                        let anchor = buffer.anchor_after(end);
 4588                        let new_selection = selection.map(|_| anchor);
 4589                        (
 4590                            ((start..end, new_text), prevent_auto_indent),
 4591                            (insert_extra_newline, new_selection),
 4592                        )
 4593                    })
 4594                    .unzip()
 4595            };
 4596
 4597            let mut auto_indent_edits = Vec::new();
 4598            let mut edits = Vec::new();
 4599            for (edit, prevent_auto_indent) in edits_with_flags {
 4600                if prevent_auto_indent {
 4601                    edits.push(edit);
 4602                } else {
 4603                    auto_indent_edits.push(edit);
 4604                }
 4605            }
 4606            if !edits.is_empty() {
 4607                this.edit(edits, cx);
 4608            }
 4609            if !auto_indent_edits.is_empty() {
 4610                this.edit_with_autoindent(auto_indent_edits, cx);
 4611            }
 4612
 4613            let buffer = this.buffer.read(cx).snapshot(cx);
 4614            let new_selections = selection_info
 4615                .into_iter()
 4616                .map(|(extra_newline_inserted, new_selection)| {
 4617                    let mut cursor = new_selection.end.to_point(&buffer);
 4618                    if extra_newline_inserted {
 4619                        cursor.row -= 1;
 4620                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4621                    }
 4622                    new_selection.map(|_| cursor)
 4623                })
 4624                .collect();
 4625
 4626            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4627            this.refresh_edit_prediction(true, false, window, cx);
 4628        });
 4629    }
 4630
 4631    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4632        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4633
 4634        let buffer = self.buffer.read(cx);
 4635        let snapshot = buffer.snapshot(cx);
 4636
 4637        let mut edits = Vec::new();
 4638        let mut rows = Vec::new();
 4639
 4640        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4641            let cursor = selection.head();
 4642            let row = cursor.row;
 4643
 4644            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4645
 4646            let newline = "\n".to_string();
 4647            edits.push((start_of_line..start_of_line, newline));
 4648
 4649            rows.push(row + rows_inserted as u32);
 4650        }
 4651
 4652        self.transact(window, cx, |editor, window, cx| {
 4653            editor.edit(edits, cx);
 4654
 4655            editor.change_selections(Default::default(), window, cx, |s| {
 4656                let mut index = 0;
 4657                s.move_cursors_with(|map, _, _| {
 4658                    let row = rows[index];
 4659                    index += 1;
 4660
 4661                    let point = Point::new(row, 0);
 4662                    let boundary = map.next_line_boundary(point).1;
 4663                    let clipped = map.clip_point(boundary, Bias::Left);
 4664
 4665                    (clipped, SelectionGoal::None)
 4666                });
 4667            });
 4668
 4669            let mut indent_edits = Vec::new();
 4670            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4671            for row in rows {
 4672                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4673                for (row, indent) in indents {
 4674                    if indent.len == 0 {
 4675                        continue;
 4676                    }
 4677
 4678                    let text = match indent.kind {
 4679                        IndentKind::Space => " ".repeat(indent.len as usize),
 4680                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4681                    };
 4682                    let point = Point::new(row.0, 0);
 4683                    indent_edits.push((point..point, text));
 4684                }
 4685            }
 4686            editor.edit(indent_edits, cx);
 4687        });
 4688    }
 4689
 4690    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4691        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4692
 4693        let buffer = self.buffer.read(cx);
 4694        let snapshot = buffer.snapshot(cx);
 4695
 4696        let mut edits = Vec::new();
 4697        let mut rows = Vec::new();
 4698        let mut rows_inserted = 0;
 4699
 4700        for selection in self.selections.all_adjusted(cx) {
 4701            let cursor = selection.head();
 4702            let row = cursor.row;
 4703
 4704            let point = Point::new(row + 1, 0);
 4705            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4706
 4707            let newline = "\n".to_string();
 4708            edits.push((start_of_line..start_of_line, newline));
 4709
 4710            rows_inserted += 1;
 4711            rows.push(row + rows_inserted);
 4712        }
 4713
 4714        self.transact(window, cx, |editor, window, cx| {
 4715            editor.edit(edits, cx);
 4716
 4717            editor.change_selections(Default::default(), window, cx, |s| {
 4718                let mut index = 0;
 4719                s.move_cursors_with(|map, _, _| {
 4720                    let row = rows[index];
 4721                    index += 1;
 4722
 4723                    let point = Point::new(row, 0);
 4724                    let boundary = map.next_line_boundary(point).1;
 4725                    let clipped = map.clip_point(boundary, Bias::Left);
 4726
 4727                    (clipped, SelectionGoal::None)
 4728                });
 4729            });
 4730
 4731            let mut indent_edits = Vec::new();
 4732            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4733            for row in rows {
 4734                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4735                for (row, indent) in indents {
 4736                    if indent.len == 0 {
 4737                        continue;
 4738                    }
 4739
 4740                    let text = match indent.kind {
 4741                        IndentKind::Space => " ".repeat(indent.len as usize),
 4742                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4743                    };
 4744                    let point = Point::new(row.0, 0);
 4745                    indent_edits.push((point..point, text));
 4746                }
 4747            }
 4748            editor.edit(indent_edits, cx);
 4749        });
 4750    }
 4751
 4752    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4753        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4754            original_indent_columns: Vec::new(),
 4755        });
 4756        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4757    }
 4758
 4759    fn insert_with_autoindent_mode(
 4760        &mut self,
 4761        text: &str,
 4762        autoindent_mode: Option<AutoindentMode>,
 4763        window: &mut Window,
 4764        cx: &mut Context<Self>,
 4765    ) {
 4766        if self.read_only(cx) {
 4767            return;
 4768        }
 4769
 4770        let text: Arc<str> = text.into();
 4771        self.transact(window, cx, |this, window, cx| {
 4772            let old_selections = this.selections.all_adjusted(cx);
 4773            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4774                let anchors = {
 4775                    let snapshot = buffer.read(cx);
 4776                    old_selections
 4777                        .iter()
 4778                        .map(|s| {
 4779                            let anchor = snapshot.anchor_after(s.head());
 4780                            s.map(|_| anchor)
 4781                        })
 4782                        .collect::<Vec<_>>()
 4783                };
 4784                buffer.edit(
 4785                    old_selections
 4786                        .iter()
 4787                        .map(|s| (s.start..s.end, text.clone())),
 4788                    autoindent_mode,
 4789                    cx,
 4790                );
 4791                anchors
 4792            });
 4793
 4794            this.change_selections(Default::default(), window, cx, |s| {
 4795                s.select_anchors(selection_anchors);
 4796            });
 4797
 4798            cx.notify();
 4799        });
 4800    }
 4801
 4802    fn trigger_completion_on_input(
 4803        &mut self,
 4804        text: &str,
 4805        trigger_in_words: bool,
 4806        window: &mut Window,
 4807        cx: &mut Context<Self>,
 4808    ) {
 4809        let completions_source = self
 4810            .context_menu
 4811            .borrow()
 4812            .as_ref()
 4813            .and_then(|menu| match menu {
 4814                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4815                CodeContextMenu::CodeActions(_) => None,
 4816            });
 4817
 4818        match completions_source {
 4819            Some(CompletionsMenuSource::Words) => {
 4820                self.show_word_completions(&ShowWordCompletions, window, cx)
 4821            }
 4822            Some(CompletionsMenuSource::Normal)
 4823            | Some(CompletionsMenuSource::SnippetChoices)
 4824            | None
 4825                if self.is_completion_trigger(
 4826                    text,
 4827                    trigger_in_words,
 4828                    completions_source.is_some(),
 4829                    cx,
 4830                ) =>
 4831            {
 4832                self.show_completions(
 4833                    &ShowCompletions {
 4834                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4835                    },
 4836                    window,
 4837                    cx,
 4838                )
 4839            }
 4840            _ => {
 4841                self.hide_context_menu(window, cx);
 4842            }
 4843        }
 4844    }
 4845
 4846    fn is_completion_trigger(
 4847        &self,
 4848        text: &str,
 4849        trigger_in_words: bool,
 4850        menu_is_open: bool,
 4851        cx: &mut Context<Self>,
 4852    ) -> bool {
 4853        let position = self.selections.newest_anchor().head();
 4854        let multibuffer = self.buffer.read(cx);
 4855        let Some(buffer) = position
 4856            .buffer_id
 4857            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4858        else {
 4859            return false;
 4860        };
 4861
 4862        if let Some(completion_provider) = &self.completion_provider {
 4863            completion_provider.is_completion_trigger(
 4864                &buffer,
 4865                position.text_anchor,
 4866                text,
 4867                trigger_in_words,
 4868                menu_is_open,
 4869                cx,
 4870            )
 4871        } else {
 4872            false
 4873        }
 4874    }
 4875
 4876    /// If any empty selections is touching the start of its innermost containing autoclose
 4877    /// region, expand it to select the brackets.
 4878    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4879        let selections = self.selections.all::<usize>(cx);
 4880        let buffer = self.buffer.read(cx).read(cx);
 4881        let new_selections = self
 4882            .selections_with_autoclose_regions(selections, &buffer)
 4883            .map(|(mut selection, region)| {
 4884                if !selection.is_empty() {
 4885                    return selection;
 4886                }
 4887
 4888                if let Some(region) = region {
 4889                    let mut range = region.range.to_offset(&buffer);
 4890                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4891                        range.start -= region.pair.start.len();
 4892                        if buffer.contains_str_at(range.start, &region.pair.start)
 4893                            && buffer.contains_str_at(range.end, &region.pair.end)
 4894                        {
 4895                            range.end += region.pair.end.len();
 4896                            selection.start = range.start;
 4897                            selection.end = range.end;
 4898
 4899                            return selection;
 4900                        }
 4901                    }
 4902                }
 4903
 4904                let always_treat_brackets_as_autoclosed = buffer
 4905                    .language_settings_at(selection.start, cx)
 4906                    .always_treat_brackets_as_autoclosed;
 4907
 4908                if !always_treat_brackets_as_autoclosed {
 4909                    return selection;
 4910                }
 4911
 4912                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4913                    for (pair, enabled) in scope.brackets() {
 4914                        if !enabled || !pair.close {
 4915                            continue;
 4916                        }
 4917
 4918                        if buffer.contains_str_at(selection.start, &pair.end) {
 4919                            let pair_start_len = pair.start.len();
 4920                            if buffer.contains_str_at(
 4921                                selection.start.saturating_sub(pair_start_len),
 4922                                &pair.start,
 4923                            ) {
 4924                                selection.start -= pair_start_len;
 4925                                selection.end += pair.end.len();
 4926
 4927                                return selection;
 4928                            }
 4929                        }
 4930                    }
 4931                }
 4932
 4933                selection
 4934            })
 4935            .collect();
 4936
 4937        drop(buffer);
 4938        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 4939            selections.select(new_selections)
 4940        });
 4941    }
 4942
 4943    /// Iterate the given selections, and for each one, find the smallest surrounding
 4944    /// autoclose region. This uses the ordering of the selections and the autoclose
 4945    /// regions to avoid repeated comparisons.
 4946    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4947        &'a self,
 4948        selections: impl IntoIterator<Item = Selection<D>>,
 4949        buffer: &'a MultiBufferSnapshot,
 4950    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4951        let mut i = 0;
 4952        let mut regions = self.autoclose_regions.as_slice();
 4953        selections.into_iter().map(move |selection| {
 4954            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4955
 4956            let mut enclosing = None;
 4957            while let Some(pair_state) = regions.get(i) {
 4958                if pair_state.range.end.to_offset(buffer) < range.start {
 4959                    regions = &regions[i + 1..];
 4960                    i = 0;
 4961                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4962                    break;
 4963                } else {
 4964                    if pair_state.selection_id == selection.id {
 4965                        enclosing = Some(pair_state);
 4966                    }
 4967                    i += 1;
 4968                }
 4969            }
 4970
 4971            (selection, enclosing)
 4972        })
 4973    }
 4974
 4975    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 4976    fn invalidate_autoclose_regions(
 4977        &mut self,
 4978        mut selections: &[Selection<Anchor>],
 4979        buffer: &MultiBufferSnapshot,
 4980    ) {
 4981        self.autoclose_regions.retain(|state| {
 4982            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 4983                return false;
 4984            }
 4985
 4986            let mut i = 0;
 4987            while let Some(selection) = selections.get(i) {
 4988                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4989                    selections = &selections[1..];
 4990                    continue;
 4991                }
 4992                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4993                    break;
 4994                }
 4995                if selection.id == state.selection_id {
 4996                    return true;
 4997                } else {
 4998                    i += 1;
 4999                }
 5000            }
 5001            false
 5002        });
 5003    }
 5004
 5005    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5006        let offset = position.to_offset(buffer);
 5007        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5008        if offset > word_range.start && kind == Some(CharKind::Word) {
 5009            Some(
 5010                buffer
 5011                    .text_for_range(word_range.start..offset)
 5012                    .collect::<String>(),
 5013            )
 5014        } else {
 5015            None
 5016        }
 5017    }
 5018
 5019    pub fn toggle_inline_values(
 5020        &mut self,
 5021        _: &ToggleInlineValues,
 5022        _: &mut Window,
 5023        cx: &mut Context<Self>,
 5024    ) {
 5025        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5026
 5027        self.refresh_inline_values(cx);
 5028    }
 5029
 5030    pub fn toggle_inlay_hints(
 5031        &mut self,
 5032        _: &ToggleInlayHints,
 5033        _: &mut Window,
 5034        cx: &mut Context<Self>,
 5035    ) {
 5036        self.refresh_inlay_hints(
 5037            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5038            cx,
 5039        );
 5040    }
 5041
 5042    pub fn inlay_hints_enabled(&self) -> bool {
 5043        self.inlay_hint_cache.enabled
 5044    }
 5045
 5046    pub fn inline_values_enabled(&self) -> bool {
 5047        self.inline_value_cache.enabled
 5048    }
 5049
 5050    #[cfg(any(test, feature = "test-support"))]
 5051    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5052        self.display_map
 5053            .read(cx)
 5054            .current_inlays()
 5055            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5056            .cloned()
 5057            .collect()
 5058    }
 5059
 5060    #[cfg(any(test, feature = "test-support"))]
 5061    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5062        self.display_map
 5063            .read(cx)
 5064            .current_inlays()
 5065            .cloned()
 5066            .collect()
 5067    }
 5068
 5069    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5070        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5071            return;
 5072        }
 5073
 5074        let reason_description = reason.description();
 5075        let ignore_debounce = matches!(
 5076            reason,
 5077            InlayHintRefreshReason::SettingsChange(_)
 5078                | InlayHintRefreshReason::Toggle(_)
 5079                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5080                | InlayHintRefreshReason::ModifiersChanged(_)
 5081        );
 5082        let (invalidate_cache, required_languages) = match reason {
 5083            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5084                match self.inlay_hint_cache.modifiers_override(enabled) {
 5085                    Some(enabled) => {
 5086                        if enabled {
 5087                            (InvalidationStrategy::RefreshRequested, None)
 5088                        } else {
 5089                            self.splice_inlays(
 5090                                &self
 5091                                    .visible_inlay_hints(cx)
 5092                                    .iter()
 5093                                    .map(|inlay| inlay.id)
 5094                                    .collect::<Vec<InlayId>>(),
 5095                                Vec::new(),
 5096                                cx,
 5097                            );
 5098                            return;
 5099                        }
 5100                    }
 5101                    None => return,
 5102                }
 5103            }
 5104            InlayHintRefreshReason::Toggle(enabled) => {
 5105                if self.inlay_hint_cache.toggle(enabled) {
 5106                    if enabled {
 5107                        (InvalidationStrategy::RefreshRequested, None)
 5108                    } else {
 5109                        self.splice_inlays(
 5110                            &self
 5111                                .visible_inlay_hints(cx)
 5112                                .iter()
 5113                                .map(|inlay| inlay.id)
 5114                                .collect::<Vec<InlayId>>(),
 5115                            Vec::new(),
 5116                            cx,
 5117                        );
 5118                        return;
 5119                    }
 5120                } else {
 5121                    return;
 5122                }
 5123            }
 5124            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5125                match self.inlay_hint_cache.update_settings(
 5126                    &self.buffer,
 5127                    new_settings,
 5128                    self.visible_inlay_hints(cx),
 5129                    cx,
 5130                ) {
 5131                    ControlFlow::Break(Some(InlaySplice {
 5132                        to_remove,
 5133                        to_insert,
 5134                    })) => {
 5135                        self.splice_inlays(&to_remove, to_insert, cx);
 5136                        return;
 5137                    }
 5138                    ControlFlow::Break(None) => return,
 5139                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5140                }
 5141            }
 5142            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5143                if let Some(InlaySplice {
 5144                    to_remove,
 5145                    to_insert,
 5146                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5147                {
 5148                    self.splice_inlays(&to_remove, to_insert, cx);
 5149                }
 5150                self.display_map.update(cx, |display_map, _| {
 5151                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5152                });
 5153                return;
 5154            }
 5155            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5156            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5157                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5158            }
 5159            InlayHintRefreshReason::RefreshRequested => {
 5160                (InvalidationStrategy::RefreshRequested, None)
 5161            }
 5162        };
 5163
 5164        if let Some(InlaySplice {
 5165            to_remove,
 5166            to_insert,
 5167        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5168            reason_description,
 5169            self.visible_excerpts(required_languages.as_ref(), cx),
 5170            invalidate_cache,
 5171            ignore_debounce,
 5172            cx,
 5173        ) {
 5174            self.splice_inlays(&to_remove, to_insert, cx);
 5175        }
 5176    }
 5177
 5178    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5179        self.display_map
 5180            .read(cx)
 5181            .current_inlays()
 5182            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5183            .cloned()
 5184            .collect()
 5185    }
 5186
 5187    pub fn visible_excerpts(
 5188        &self,
 5189        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5190        cx: &mut Context<Editor>,
 5191    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5192        let Some(project) = self.project.as_ref() else {
 5193            return HashMap::default();
 5194        };
 5195        let project = project.read(cx);
 5196        let multi_buffer = self.buffer().read(cx);
 5197        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5198        let multi_buffer_visible_start = self
 5199            .scroll_manager
 5200            .anchor()
 5201            .anchor
 5202            .to_point(&multi_buffer_snapshot);
 5203        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5204            multi_buffer_visible_start
 5205                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5206            Bias::Left,
 5207        );
 5208        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5209        multi_buffer_snapshot
 5210            .range_to_buffer_ranges(multi_buffer_visible_range)
 5211            .into_iter()
 5212            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5213            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5214                let buffer_file = project::File::from_dyn(buffer.file())?;
 5215                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5216                let worktree_entry = buffer_worktree
 5217                    .read(cx)
 5218                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5219                if worktree_entry.is_ignored {
 5220                    return None;
 5221                }
 5222
 5223                let language = buffer.language()?;
 5224                if let Some(restrict_to_languages) = restrict_to_languages {
 5225                    if !restrict_to_languages.contains(language) {
 5226                        return None;
 5227                    }
 5228                }
 5229                Some((
 5230                    excerpt_id,
 5231                    (
 5232                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5233                        buffer.version().clone(),
 5234                        excerpt_visible_range,
 5235                    ),
 5236                ))
 5237            })
 5238            .collect()
 5239    }
 5240
 5241    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5242        TextLayoutDetails {
 5243            text_system: window.text_system().clone(),
 5244            editor_style: self.style.clone().unwrap(),
 5245            rem_size: window.rem_size(),
 5246            scroll_anchor: self.scroll_manager.anchor(),
 5247            visible_rows: self.visible_line_count(),
 5248            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5249        }
 5250    }
 5251
 5252    pub fn splice_inlays(
 5253        &self,
 5254        to_remove: &[InlayId],
 5255        to_insert: Vec<Inlay>,
 5256        cx: &mut Context<Self>,
 5257    ) {
 5258        self.display_map.update(cx, |display_map, cx| {
 5259            display_map.splice_inlays(to_remove, to_insert, cx)
 5260        });
 5261        cx.notify();
 5262    }
 5263
 5264    fn trigger_on_type_formatting(
 5265        &self,
 5266        input: String,
 5267        window: &mut Window,
 5268        cx: &mut Context<Self>,
 5269    ) -> Option<Task<Result<()>>> {
 5270        if input.len() != 1 {
 5271            return None;
 5272        }
 5273
 5274        let project = self.project.as_ref()?;
 5275        let position = self.selections.newest_anchor().head();
 5276        let (buffer, buffer_position) = self
 5277            .buffer
 5278            .read(cx)
 5279            .text_anchor_for_position(position, cx)?;
 5280
 5281        let settings = language_settings::language_settings(
 5282            buffer
 5283                .read(cx)
 5284                .language_at(buffer_position)
 5285                .map(|l| l.name()),
 5286            buffer.read(cx).file(),
 5287            cx,
 5288        );
 5289        if !settings.use_on_type_format {
 5290            return None;
 5291        }
 5292
 5293        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5294        // hence we do LSP request & edit on host side only — add formats to host's history.
 5295        let push_to_lsp_host_history = true;
 5296        // If this is not the host, append its history with new edits.
 5297        let push_to_client_history = project.read(cx).is_via_collab();
 5298
 5299        let on_type_formatting = project.update(cx, |project, cx| {
 5300            project.on_type_format(
 5301                buffer.clone(),
 5302                buffer_position,
 5303                input,
 5304                push_to_lsp_host_history,
 5305                cx,
 5306            )
 5307        });
 5308        Some(cx.spawn_in(window, async move |editor, cx| {
 5309            if let Some(transaction) = on_type_formatting.await? {
 5310                if push_to_client_history {
 5311                    buffer
 5312                        .update(cx, |buffer, _| {
 5313                            buffer.push_transaction(transaction, Instant::now());
 5314                            buffer.finalize_last_transaction();
 5315                        })
 5316                        .ok();
 5317                }
 5318                editor.update(cx, |editor, cx| {
 5319                    editor.refresh_document_highlights(cx);
 5320                })?;
 5321            }
 5322            Ok(())
 5323        }))
 5324    }
 5325
 5326    pub fn show_word_completions(
 5327        &mut self,
 5328        _: &ShowWordCompletions,
 5329        window: &mut Window,
 5330        cx: &mut Context<Self>,
 5331    ) {
 5332        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5333    }
 5334
 5335    pub fn show_completions(
 5336        &mut self,
 5337        options: &ShowCompletions,
 5338        window: &mut Window,
 5339        cx: &mut Context<Self>,
 5340    ) {
 5341        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5342    }
 5343
 5344    fn open_or_update_completions_menu(
 5345        &mut self,
 5346        requested_source: Option<CompletionsMenuSource>,
 5347        trigger: Option<&str>,
 5348        window: &mut Window,
 5349        cx: &mut Context<Self>,
 5350    ) {
 5351        if self.pending_rename.is_some() {
 5352            return;
 5353        }
 5354
 5355        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5356
 5357        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5358        // inserted and selected. To handle that case, the start of the selection is used so that
 5359        // the menu starts with all choices.
 5360        let position = self
 5361            .selections
 5362            .newest_anchor()
 5363            .start
 5364            .bias_right(&multibuffer_snapshot);
 5365        if position.diff_base_anchor.is_some() {
 5366            return;
 5367        }
 5368        let (buffer, buffer_position) =
 5369            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5370                output
 5371            } else {
 5372                return;
 5373            };
 5374        let buffer_snapshot = buffer.read(cx).snapshot();
 5375
 5376        let query: Option<Arc<String>> =
 5377            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5378
 5379        drop(multibuffer_snapshot);
 5380
 5381        let provider = match requested_source {
 5382            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5383            Some(CompletionsMenuSource::Words) => None,
 5384            Some(CompletionsMenuSource::SnippetChoices) => {
 5385                log::error!("bug: SnippetChoices requested_source is not handled");
 5386                None
 5387            }
 5388        };
 5389
 5390        let sort_completions = provider
 5391            .as_ref()
 5392            .map_or(false, |provider| provider.sort_completions());
 5393
 5394        let filter_completions = provider
 5395            .as_ref()
 5396            .map_or(true, |provider| provider.filter_completions());
 5397
 5398        let trigger_kind = match trigger {
 5399            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5400                CompletionTriggerKind::TRIGGER_CHARACTER
 5401            }
 5402            _ => CompletionTriggerKind::INVOKED,
 5403        };
 5404        let completion_context = CompletionContext {
 5405            trigger_character: trigger.and_then(|trigger| {
 5406                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5407                    Some(String::from(trigger))
 5408                } else {
 5409                    None
 5410                }
 5411            }),
 5412            trigger_kind,
 5413        };
 5414
 5415        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5416        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5417        // involve trigger chars, so this is skipped in that case.
 5418        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5419        {
 5420            let menu_is_open = matches!(
 5421                self.context_menu.borrow().as_ref(),
 5422                Some(CodeContextMenu::Completions(_))
 5423            );
 5424            if menu_is_open {
 5425                self.hide_context_menu(window, cx);
 5426            }
 5427        }
 5428
 5429        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5430            if filter_completions {
 5431                menu.filter(query.clone(), provider.clone(), window, cx);
 5432            }
 5433            // When `is_incomplete` is false, no need to re-query completions when the current query
 5434            // is a suffix of the initial query.
 5435            if !menu.is_incomplete {
 5436                // If the new query is a suffix of the old query (typing more characters) and
 5437                // the previous result was complete, the existing completions can be filtered.
 5438                //
 5439                // Note that this is always true for snippet completions.
 5440                let query_matches = match (&menu.initial_query, &query) {
 5441                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5442                    (None, _) => true,
 5443                    _ => false,
 5444                };
 5445                if query_matches {
 5446                    let position_matches = if menu.initial_position == position {
 5447                        true
 5448                    } else {
 5449                        let snapshot = self.buffer.read(cx).read(cx);
 5450                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5451                    };
 5452                    if position_matches {
 5453                        return;
 5454                    }
 5455                }
 5456            }
 5457        };
 5458
 5459        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5460            buffer_snapshot.surrounding_word(buffer_position, false)
 5461        {
 5462            let word_to_exclude = buffer_snapshot
 5463                .text_for_range(word_range.clone())
 5464                .collect::<String>();
 5465            (
 5466                buffer_snapshot.anchor_before(word_range.start)
 5467                    ..buffer_snapshot.anchor_after(buffer_position),
 5468                Some(word_to_exclude),
 5469            )
 5470        } else {
 5471            (buffer_position..buffer_position, None)
 5472        };
 5473
 5474        let language = buffer_snapshot
 5475            .language_at(buffer_position)
 5476            .map(|language| language.name());
 5477
 5478        let completion_settings =
 5479            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5480
 5481        let show_completion_documentation = buffer_snapshot
 5482            .settings_at(buffer_position, cx)
 5483            .show_completion_documentation;
 5484
 5485        // The document can be large, so stay in reasonable bounds when searching for words,
 5486        // otherwise completion pop-up might be slow to appear.
 5487        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5488        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5489        let min_word_search = buffer_snapshot.clip_point(
 5490            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5491            Bias::Left,
 5492        );
 5493        let max_word_search = buffer_snapshot.clip_point(
 5494            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5495            Bias::Right,
 5496        );
 5497        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5498            ..buffer_snapshot.point_to_offset(max_word_search);
 5499
 5500        let skip_digits = query
 5501            .as_ref()
 5502            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5503
 5504        let (mut words, provider_responses) = match &provider {
 5505            Some(provider) => {
 5506                let provider_responses = provider.completions(
 5507                    position.excerpt_id,
 5508                    &buffer,
 5509                    buffer_position,
 5510                    completion_context,
 5511                    window,
 5512                    cx,
 5513                );
 5514
 5515                let words = match completion_settings.words {
 5516                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5517                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5518                        .background_spawn(async move {
 5519                            buffer_snapshot.words_in_range(WordsQuery {
 5520                                fuzzy_contents: None,
 5521                                range: word_search_range,
 5522                                skip_digits,
 5523                            })
 5524                        }),
 5525                };
 5526
 5527                (words, provider_responses)
 5528            }
 5529            None => (
 5530                cx.background_spawn(async move {
 5531                    buffer_snapshot.words_in_range(WordsQuery {
 5532                        fuzzy_contents: None,
 5533                        range: word_search_range,
 5534                        skip_digits,
 5535                    })
 5536                }),
 5537                Task::ready(Ok(Vec::new())),
 5538            ),
 5539        };
 5540
 5541        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5542
 5543        let id = post_inc(&mut self.next_completion_id);
 5544        let task = cx.spawn_in(window, async move |editor, cx| {
 5545            let Ok(()) = editor.update(cx, |this, _| {
 5546                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5547            }) else {
 5548                return;
 5549            };
 5550
 5551            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5552            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5553            let mut completions = Vec::new();
 5554            let mut is_incomplete = false;
 5555            if let Some(provider_responses) = provider_responses.await.log_err() {
 5556                if !provider_responses.is_empty() {
 5557                    for response in provider_responses {
 5558                        completions.extend(response.completions);
 5559                        is_incomplete = is_incomplete || response.is_incomplete;
 5560                    }
 5561                    if completion_settings.words == WordsCompletionMode::Fallback {
 5562                        words = Task::ready(BTreeMap::default());
 5563                    }
 5564                }
 5565            }
 5566
 5567            let mut words = words.await;
 5568            if let Some(word_to_exclude) = &word_to_exclude {
 5569                words.remove(word_to_exclude);
 5570            }
 5571            for lsp_completion in &completions {
 5572                words.remove(&lsp_completion.new_text);
 5573            }
 5574            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5575                replace_range: word_replace_range.clone(),
 5576                new_text: word.clone(),
 5577                label: CodeLabel::plain(word, None),
 5578                icon_path: None,
 5579                documentation: None,
 5580                source: CompletionSource::BufferWord {
 5581                    word_range,
 5582                    resolved: false,
 5583                },
 5584                insert_text_mode: Some(InsertTextMode::AS_IS),
 5585                confirm: None,
 5586            }));
 5587
 5588            let menu = if completions.is_empty() {
 5589                None
 5590            } else {
 5591                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5592                    let languages = editor
 5593                        .workspace
 5594                        .as_ref()
 5595                        .and_then(|(workspace, _)| workspace.upgrade())
 5596                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5597                    let menu = CompletionsMenu::new(
 5598                        id,
 5599                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5600                        sort_completions,
 5601                        show_completion_documentation,
 5602                        position,
 5603                        query.clone(),
 5604                        is_incomplete,
 5605                        buffer.clone(),
 5606                        completions.into(),
 5607                        snippet_sort_order,
 5608                        languages,
 5609                        language,
 5610                        cx,
 5611                    );
 5612
 5613                    let query = if filter_completions { query } else { None };
 5614                    let matches_task = if let Some(query) = query {
 5615                        menu.do_async_filtering(query, cx)
 5616                    } else {
 5617                        Task::ready(menu.unfiltered_matches())
 5618                    };
 5619                    (menu, matches_task)
 5620                }) else {
 5621                    return;
 5622                };
 5623
 5624                let matches = matches_task.await;
 5625
 5626                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5627                    // Newer menu already set, so exit.
 5628                    match editor.context_menu.borrow().as_ref() {
 5629                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5630                            if prev_menu.id > id {
 5631                                return;
 5632                            }
 5633                        }
 5634                        _ => {}
 5635                    };
 5636
 5637                    // Only valid to take prev_menu because it the new menu is immediately set
 5638                    // below, or the menu is hidden.
 5639                    match editor.context_menu.borrow_mut().take() {
 5640                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5641                            let position_matches =
 5642                                if prev_menu.initial_position == menu.initial_position {
 5643                                    true
 5644                                } else {
 5645                                    let snapshot = editor.buffer.read(cx).read(cx);
 5646                                    prev_menu.initial_position.to_offset(&snapshot)
 5647                                        == menu.initial_position.to_offset(&snapshot)
 5648                                };
 5649                            if position_matches {
 5650                                // Preserve markdown cache before `set_filter_results` because it will
 5651                                // try to populate the documentation cache.
 5652                                menu.preserve_markdown_cache(prev_menu);
 5653                            }
 5654                        }
 5655                        _ => {}
 5656                    };
 5657
 5658                    menu.set_filter_results(matches, provider, window, cx);
 5659                }) else {
 5660                    return;
 5661                };
 5662
 5663                menu.visible().then_some(menu)
 5664            };
 5665
 5666            editor
 5667                .update_in(cx, |editor, window, cx| {
 5668                    if editor.focus_handle.is_focused(window) {
 5669                        if let Some(menu) = menu {
 5670                            *editor.context_menu.borrow_mut() =
 5671                                Some(CodeContextMenu::Completions(menu));
 5672
 5673                            crate::hover_popover::hide_hover(editor, cx);
 5674                            if editor.show_edit_predictions_in_menu() {
 5675                                editor.update_visible_edit_prediction(window, cx);
 5676                            } else {
 5677                                editor.discard_edit_prediction(false, cx);
 5678                            }
 5679
 5680                            cx.notify();
 5681                            return;
 5682                        }
 5683                    }
 5684
 5685                    if editor.completion_tasks.len() <= 1 {
 5686                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5687                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5688                        // If it was already hidden and we don't show edit predictions in the menu,
 5689                        // we should also show the edit prediction when available.
 5690                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5691                            editor.update_visible_edit_prediction(window, cx);
 5692                        }
 5693                    }
 5694                })
 5695                .ok();
 5696        });
 5697
 5698        self.completion_tasks.push((id, task));
 5699    }
 5700
 5701    #[cfg(feature = "test-support")]
 5702    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5703        let menu = self.context_menu.borrow();
 5704        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5705            let completions = menu.completions.borrow();
 5706            Some(completions.to_vec())
 5707        } else {
 5708            None
 5709        }
 5710    }
 5711
 5712    pub fn with_completions_menu_matching_id<R>(
 5713        &self,
 5714        id: CompletionId,
 5715        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5716    ) -> R {
 5717        let mut context_menu = self.context_menu.borrow_mut();
 5718        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5719            return f(None);
 5720        };
 5721        if completions_menu.id != id {
 5722            return f(None);
 5723        }
 5724        f(Some(completions_menu))
 5725    }
 5726
 5727    pub fn confirm_completion(
 5728        &mut self,
 5729        action: &ConfirmCompletion,
 5730        window: &mut Window,
 5731        cx: &mut Context<Self>,
 5732    ) -> Option<Task<Result<()>>> {
 5733        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5734        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5735    }
 5736
 5737    pub fn confirm_completion_insert(
 5738        &mut self,
 5739        _: &ConfirmCompletionInsert,
 5740        window: &mut Window,
 5741        cx: &mut Context<Self>,
 5742    ) -> Option<Task<Result<()>>> {
 5743        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5744        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5745    }
 5746
 5747    pub fn confirm_completion_replace(
 5748        &mut self,
 5749        _: &ConfirmCompletionReplace,
 5750        window: &mut Window,
 5751        cx: &mut Context<Self>,
 5752    ) -> Option<Task<Result<()>>> {
 5753        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5754        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5755    }
 5756
 5757    pub fn compose_completion(
 5758        &mut self,
 5759        action: &ComposeCompletion,
 5760        window: &mut Window,
 5761        cx: &mut Context<Self>,
 5762    ) -> Option<Task<Result<()>>> {
 5763        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5764        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5765    }
 5766
 5767    fn do_completion(
 5768        &mut self,
 5769        item_ix: Option<usize>,
 5770        intent: CompletionIntent,
 5771        window: &mut Window,
 5772        cx: &mut Context<Editor>,
 5773    ) -> Option<Task<Result<()>>> {
 5774        use language::ToOffset as _;
 5775
 5776        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5777        else {
 5778            return None;
 5779        };
 5780
 5781        let candidate_id = {
 5782            let entries = completions_menu.entries.borrow();
 5783            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5784            if self.show_edit_predictions_in_menu() {
 5785                self.discard_edit_prediction(true, cx);
 5786            }
 5787            mat.candidate_id
 5788        };
 5789
 5790        let completion = completions_menu
 5791            .completions
 5792            .borrow()
 5793            .get(candidate_id)?
 5794            .clone();
 5795        cx.stop_propagation();
 5796
 5797        let buffer_handle = completions_menu.buffer.clone();
 5798
 5799        let CompletionEdit {
 5800            new_text,
 5801            snippet,
 5802            replace_range,
 5803        } = process_completion_for_edit(
 5804            &completion,
 5805            intent,
 5806            &buffer_handle,
 5807            &completions_menu.initial_position.text_anchor,
 5808            cx,
 5809        );
 5810
 5811        let buffer = buffer_handle.read(cx);
 5812        let snapshot = self.buffer.read(cx).snapshot(cx);
 5813        let newest_anchor = self.selections.newest_anchor();
 5814        let replace_range_multibuffer = {
 5815            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5816            let multibuffer_anchor = snapshot
 5817                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5818                .unwrap()
 5819                ..snapshot
 5820                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5821                    .unwrap();
 5822            multibuffer_anchor.start.to_offset(&snapshot)
 5823                ..multibuffer_anchor.end.to_offset(&snapshot)
 5824        };
 5825        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5826            return None;
 5827        }
 5828
 5829        let old_text = buffer
 5830            .text_for_range(replace_range.clone())
 5831            .collect::<String>();
 5832        let lookbehind = newest_anchor
 5833            .start
 5834            .text_anchor
 5835            .to_offset(buffer)
 5836            .saturating_sub(replace_range.start);
 5837        let lookahead = replace_range
 5838            .end
 5839            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5840        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5841        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5842
 5843        let selections = self.selections.all::<usize>(cx);
 5844        let mut ranges = Vec::new();
 5845        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5846
 5847        for selection in &selections {
 5848            let range = if selection.id == newest_anchor.id {
 5849                replace_range_multibuffer.clone()
 5850            } else {
 5851                let mut range = selection.range();
 5852
 5853                // if prefix is present, don't duplicate it
 5854                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5855                    range.start = range.start.saturating_sub(lookbehind);
 5856
 5857                    // if suffix is also present, mimic the newest cursor and replace it
 5858                    if selection.id != newest_anchor.id
 5859                        && snapshot.contains_str_at(range.end, suffix)
 5860                    {
 5861                        range.end += lookahead;
 5862                    }
 5863                }
 5864                range
 5865            };
 5866
 5867            ranges.push(range.clone());
 5868
 5869            if !self.linked_edit_ranges.is_empty() {
 5870                let start_anchor = snapshot.anchor_before(range.start);
 5871                let end_anchor = snapshot.anchor_after(range.end);
 5872                if let Some(ranges) = self
 5873                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5874                {
 5875                    for (buffer, edits) in ranges {
 5876                        linked_edits
 5877                            .entry(buffer.clone())
 5878                            .or_default()
 5879                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5880                    }
 5881                }
 5882            }
 5883        }
 5884
 5885        let common_prefix_len = old_text
 5886            .chars()
 5887            .zip(new_text.chars())
 5888            .take_while(|(a, b)| a == b)
 5889            .map(|(a, _)| a.len_utf8())
 5890            .sum::<usize>();
 5891
 5892        cx.emit(EditorEvent::InputHandled {
 5893            utf16_range_to_replace: None,
 5894            text: new_text[common_prefix_len..].into(),
 5895        });
 5896
 5897        self.transact(window, cx, |editor, window, cx| {
 5898            if let Some(mut snippet) = snippet {
 5899                snippet.text = new_text.to_string();
 5900                editor
 5901                    .insert_snippet(&ranges, snippet, window, cx)
 5902                    .log_err();
 5903            } else {
 5904                editor.buffer.update(cx, |multi_buffer, cx| {
 5905                    let auto_indent = match completion.insert_text_mode {
 5906                        Some(InsertTextMode::AS_IS) => None,
 5907                        _ => editor.autoindent_mode.clone(),
 5908                    };
 5909                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5910                    multi_buffer.edit(edits, auto_indent, cx);
 5911                });
 5912            }
 5913            for (buffer, edits) in linked_edits {
 5914                buffer.update(cx, |buffer, cx| {
 5915                    let snapshot = buffer.snapshot();
 5916                    let edits = edits
 5917                        .into_iter()
 5918                        .map(|(range, text)| {
 5919                            use text::ToPoint as TP;
 5920                            let end_point = TP::to_point(&range.end, &snapshot);
 5921                            let start_point = TP::to_point(&range.start, &snapshot);
 5922                            (start_point..end_point, text)
 5923                        })
 5924                        .sorted_by_key(|(range, _)| range.start);
 5925                    buffer.edit(edits, None, cx);
 5926                })
 5927            }
 5928
 5929            editor.refresh_edit_prediction(true, false, window, cx);
 5930        });
 5931        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), &snapshot);
 5932
 5933        let show_new_completions_on_confirm = completion
 5934            .confirm
 5935            .as_ref()
 5936            .map_or(false, |confirm| confirm(intent, window, cx));
 5937        if show_new_completions_on_confirm {
 5938            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5939        }
 5940
 5941        let provider = self.completion_provider.as_ref()?;
 5942        drop(completion);
 5943        let apply_edits = provider.apply_additional_edits_for_completion(
 5944            buffer_handle,
 5945            completions_menu.completions.clone(),
 5946            candidate_id,
 5947            true,
 5948            cx,
 5949        );
 5950
 5951        let editor_settings = EditorSettings::get_global(cx);
 5952        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5953            // After the code completion is finished, users often want to know what signatures are needed.
 5954            // so we should automatically call signature_help
 5955            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5956        }
 5957
 5958        Some(cx.foreground_executor().spawn(async move {
 5959            apply_edits.await?;
 5960            Ok(())
 5961        }))
 5962    }
 5963
 5964    pub fn toggle_code_actions(
 5965        &mut self,
 5966        action: &ToggleCodeActions,
 5967        window: &mut Window,
 5968        cx: &mut Context<Self>,
 5969    ) {
 5970        let quick_launch = action.quick_launch;
 5971        let mut context_menu = self.context_menu.borrow_mut();
 5972        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5973            if code_actions.deployed_from == action.deployed_from {
 5974                // Toggle if we're selecting the same one
 5975                *context_menu = None;
 5976                cx.notify();
 5977                return;
 5978            } else {
 5979                // Otherwise, clear it and start a new one
 5980                *context_menu = None;
 5981                cx.notify();
 5982            }
 5983        }
 5984        drop(context_menu);
 5985        let snapshot = self.snapshot(window, cx);
 5986        let deployed_from = action.deployed_from.clone();
 5987        let action = action.clone();
 5988        self.completion_tasks.clear();
 5989        self.discard_edit_prediction(false, cx);
 5990
 5991        let multibuffer_point = match &action.deployed_from {
 5992            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5993                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5994            }
 5995            _ => self.selections.newest::<Point>(cx).head(),
 5996        };
 5997        let Some((buffer, buffer_row)) = snapshot
 5998            .buffer_snapshot
 5999            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6000            .and_then(|(buffer_snapshot, range)| {
 6001                self.buffer()
 6002                    .read(cx)
 6003                    .buffer(buffer_snapshot.remote_id())
 6004                    .map(|buffer| (buffer, range.start.row))
 6005            })
 6006        else {
 6007            return;
 6008        };
 6009        let buffer_id = buffer.read(cx).remote_id();
 6010        let tasks = self
 6011            .tasks
 6012            .get(&(buffer_id, buffer_row))
 6013            .map(|t| Arc::new(t.to_owned()));
 6014
 6015        if !self.focus_handle.is_focused(window) {
 6016            return;
 6017        }
 6018        let project = self.project.clone();
 6019
 6020        let code_actions_task = match deployed_from {
 6021            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6022            _ => self.code_actions(buffer_row, window, cx),
 6023        };
 6024
 6025        let runnable_task = match deployed_from {
 6026            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6027            _ => {
 6028                let mut task_context_task = Task::ready(None);
 6029                if let Some(tasks) = &tasks {
 6030                    if let Some(project) = project {
 6031                        task_context_task =
 6032                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 6033                    }
 6034                }
 6035
 6036                cx.spawn_in(window, {
 6037                    let buffer = buffer.clone();
 6038                    async move |editor, cx| {
 6039                        let task_context = task_context_task.await;
 6040
 6041                        let resolved_tasks =
 6042                            tasks
 6043                                .zip(task_context.clone())
 6044                                .map(|(tasks, task_context)| ResolvedTasks {
 6045                                    templates: tasks.resolve(&task_context).collect(),
 6046                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6047                                        multibuffer_point.row,
 6048                                        tasks.column,
 6049                                    )),
 6050                                });
 6051                        let debug_scenarios = editor
 6052                            .update(cx, |editor, cx| {
 6053                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6054                            })?
 6055                            .await;
 6056                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6057                    }
 6058                })
 6059            }
 6060        };
 6061
 6062        cx.spawn_in(window, async move |editor, cx| {
 6063            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6064            let code_actions = code_actions_task.await;
 6065            let spawn_straight_away = quick_launch
 6066                && resolved_tasks
 6067                    .as_ref()
 6068                    .map_or(false, |tasks| tasks.templates.len() == 1)
 6069                && code_actions
 6070                    .as_ref()
 6071                    .map_or(true, |actions| actions.is_empty())
 6072                && debug_scenarios.is_empty();
 6073
 6074            editor.update_in(cx, |editor, window, cx| {
 6075                crate::hover_popover::hide_hover(editor, cx);
 6076                let actions = CodeActionContents::new(
 6077                    resolved_tasks,
 6078                    code_actions,
 6079                    debug_scenarios,
 6080                    task_context.unwrap_or_default(),
 6081                );
 6082
 6083                // Don't show the menu if there are no actions available
 6084                if actions.is_empty() {
 6085                    cx.notify();
 6086                    return Task::ready(Ok(()));
 6087                }
 6088
 6089                *editor.context_menu.borrow_mut() =
 6090                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6091                        buffer,
 6092                        actions,
 6093                        selected_item: Default::default(),
 6094                        scroll_handle: UniformListScrollHandle::default(),
 6095                        deployed_from,
 6096                    }));
 6097                cx.notify();
 6098                if spawn_straight_away {
 6099                    if let Some(task) = editor.confirm_code_action(
 6100                        &ConfirmCodeAction { item_ix: Some(0) },
 6101                        window,
 6102                        cx,
 6103                    ) {
 6104                        return task;
 6105                    }
 6106                }
 6107
 6108                Task::ready(Ok(()))
 6109            })
 6110        })
 6111        .detach_and_log_err(cx);
 6112    }
 6113
 6114    fn debug_scenarios(
 6115        &mut self,
 6116        resolved_tasks: &Option<ResolvedTasks>,
 6117        buffer: &Entity<Buffer>,
 6118        cx: &mut App,
 6119    ) -> Task<Vec<task::DebugScenario>> {
 6120        maybe!({
 6121            let project = self.project.as_ref()?;
 6122            let dap_store = project.read(cx).dap_store();
 6123            let mut scenarios = vec![];
 6124            let resolved_tasks = resolved_tasks.as_ref()?;
 6125            let buffer = buffer.read(cx);
 6126            let language = buffer.language()?;
 6127            let file = buffer.file();
 6128            let debug_adapter = language_settings(language.name().into(), file, cx)
 6129                .debuggers
 6130                .first()
 6131                .map(SharedString::from)
 6132                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6133
 6134            dap_store.update(cx, |dap_store, cx| {
 6135                for (_, task) in &resolved_tasks.templates {
 6136                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6137                        task.original_task().clone(),
 6138                        debug_adapter.clone().into(),
 6139                        task.display_label().to_owned().into(),
 6140                        cx,
 6141                    );
 6142                    scenarios.push(maybe_scenario);
 6143                }
 6144            });
 6145            Some(cx.background_spawn(async move {
 6146                let scenarios = futures::future::join_all(scenarios)
 6147                    .await
 6148                    .into_iter()
 6149                    .flatten()
 6150                    .collect::<Vec<_>>();
 6151                scenarios
 6152            }))
 6153        })
 6154        .unwrap_or_else(|| Task::ready(vec![]))
 6155    }
 6156
 6157    fn code_actions(
 6158        &mut self,
 6159        buffer_row: u32,
 6160        window: &mut Window,
 6161        cx: &mut Context<Self>,
 6162    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6163        let mut task = self.code_actions_task.take();
 6164        cx.spawn_in(window, async move |editor, cx| {
 6165            while let Some(prev_task) = task {
 6166                prev_task.await.log_err();
 6167                task = editor
 6168                    .update(cx, |this, _| this.code_actions_task.take())
 6169                    .ok()?;
 6170            }
 6171
 6172            editor
 6173                .update(cx, |editor, cx| {
 6174                    editor
 6175                        .available_code_actions
 6176                        .clone()
 6177                        .and_then(|(location, code_actions)| {
 6178                            let snapshot = location.buffer.read(cx).snapshot();
 6179                            let point_range = location.range.to_point(&snapshot);
 6180                            let point_range = point_range.start.row..=point_range.end.row;
 6181                            if point_range.contains(&buffer_row) {
 6182                                Some(code_actions)
 6183                            } else {
 6184                                None
 6185                            }
 6186                        })
 6187                })
 6188                .ok()
 6189                .flatten()
 6190        })
 6191    }
 6192
 6193    pub fn confirm_code_action(
 6194        &mut self,
 6195        action: &ConfirmCodeAction,
 6196        window: &mut Window,
 6197        cx: &mut Context<Self>,
 6198    ) -> Option<Task<Result<()>>> {
 6199        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6200
 6201        let actions_menu =
 6202            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6203                menu
 6204            } else {
 6205                return None;
 6206            };
 6207
 6208        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6209        let action = actions_menu.actions.get(action_ix)?;
 6210        let title = action.label();
 6211        let buffer = actions_menu.buffer;
 6212        let workspace = self.workspace()?;
 6213
 6214        match action {
 6215            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6216                workspace.update(cx, |workspace, cx| {
 6217                    workspace.schedule_resolved_task(
 6218                        task_source_kind,
 6219                        resolved_task,
 6220                        false,
 6221                        window,
 6222                        cx,
 6223                    );
 6224
 6225                    Some(Task::ready(Ok(())))
 6226                })
 6227            }
 6228            CodeActionsItem::CodeAction {
 6229                excerpt_id,
 6230                action,
 6231                provider,
 6232            } => {
 6233                let apply_code_action =
 6234                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6235                let workspace = workspace.downgrade();
 6236                Some(cx.spawn_in(window, async move |editor, cx| {
 6237                    let project_transaction = apply_code_action.await?;
 6238                    Self::open_project_transaction(
 6239                        &editor,
 6240                        workspace,
 6241                        project_transaction,
 6242                        title,
 6243                        cx,
 6244                    )
 6245                    .await
 6246                }))
 6247            }
 6248            CodeActionsItem::DebugScenario(scenario) => {
 6249                let context = actions_menu.actions.context.clone();
 6250
 6251                workspace.update(cx, |workspace, cx| {
 6252                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6253                    workspace.start_debug_session(
 6254                        scenario,
 6255                        context,
 6256                        Some(buffer),
 6257                        None,
 6258                        window,
 6259                        cx,
 6260                    );
 6261                });
 6262                Some(Task::ready(Ok(())))
 6263            }
 6264        }
 6265    }
 6266
 6267    pub async fn open_project_transaction(
 6268        this: &WeakEntity<Editor>,
 6269        workspace: WeakEntity<Workspace>,
 6270        transaction: ProjectTransaction,
 6271        title: String,
 6272        cx: &mut AsyncWindowContext,
 6273    ) -> Result<()> {
 6274        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6275        cx.update(|_, cx| {
 6276            entries.sort_unstable_by_key(|(buffer, _)| {
 6277                buffer.read(cx).file().map(|f| f.path().clone())
 6278            });
 6279        })?;
 6280
 6281        // If the project transaction's edits are all contained within this editor, then
 6282        // avoid opening a new editor to display them.
 6283
 6284        if let Some((buffer, transaction)) = entries.first() {
 6285            if entries.len() == 1 {
 6286                let excerpt = this.update(cx, |editor, cx| {
 6287                    editor
 6288                        .buffer()
 6289                        .read(cx)
 6290                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6291                })?;
 6292                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6293                    if excerpted_buffer == *buffer {
 6294                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6295                            let excerpt_range = excerpt_range.to_offset(buffer);
 6296                            buffer
 6297                                .edited_ranges_for_transaction::<usize>(transaction)
 6298                                .all(|range| {
 6299                                    excerpt_range.start <= range.start
 6300                                        && excerpt_range.end >= range.end
 6301                                })
 6302                        })?;
 6303
 6304                        if all_edits_within_excerpt {
 6305                            return Ok(());
 6306                        }
 6307                    }
 6308                }
 6309            }
 6310        } else {
 6311            return Ok(());
 6312        }
 6313
 6314        let mut ranges_to_highlight = Vec::new();
 6315        let excerpt_buffer = cx.new(|cx| {
 6316            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6317            for (buffer_handle, transaction) in &entries {
 6318                let edited_ranges = buffer_handle
 6319                    .read(cx)
 6320                    .edited_ranges_for_transaction::<Point>(transaction)
 6321                    .collect::<Vec<_>>();
 6322                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6323                    PathKey::for_buffer(buffer_handle, cx),
 6324                    buffer_handle.clone(),
 6325                    edited_ranges,
 6326                    DEFAULT_MULTIBUFFER_CONTEXT,
 6327                    cx,
 6328                );
 6329
 6330                ranges_to_highlight.extend(ranges);
 6331            }
 6332            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6333            multibuffer
 6334        })?;
 6335
 6336        workspace.update_in(cx, |workspace, window, cx| {
 6337            let project = workspace.project().clone();
 6338            let editor =
 6339                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6340            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6341            editor.update(cx, |editor, cx| {
 6342                editor.highlight_background::<Self>(
 6343                    &ranges_to_highlight,
 6344                    |theme| theme.colors().editor_highlighted_line_background,
 6345                    cx,
 6346                );
 6347            });
 6348        })?;
 6349
 6350        Ok(())
 6351    }
 6352
 6353    pub fn clear_code_action_providers(&mut self) {
 6354        self.code_action_providers.clear();
 6355        self.available_code_actions.take();
 6356    }
 6357
 6358    pub fn add_code_action_provider(
 6359        &mut self,
 6360        provider: Rc<dyn CodeActionProvider>,
 6361        window: &mut Window,
 6362        cx: &mut Context<Self>,
 6363    ) {
 6364        if self
 6365            .code_action_providers
 6366            .iter()
 6367            .any(|existing_provider| existing_provider.id() == provider.id())
 6368        {
 6369            return;
 6370        }
 6371
 6372        self.code_action_providers.push(provider);
 6373        self.refresh_code_actions(window, cx);
 6374    }
 6375
 6376    pub fn remove_code_action_provider(
 6377        &mut self,
 6378        id: Arc<str>,
 6379        window: &mut Window,
 6380        cx: &mut Context<Self>,
 6381    ) {
 6382        self.code_action_providers
 6383            .retain(|provider| provider.id() != id);
 6384        self.refresh_code_actions(window, cx);
 6385    }
 6386
 6387    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6388        !self.code_action_providers.is_empty()
 6389            && EditorSettings::get_global(cx).toolbar.code_actions
 6390    }
 6391
 6392    pub fn has_available_code_actions(&self) -> bool {
 6393        self.available_code_actions
 6394            .as_ref()
 6395            .is_some_and(|(_, actions)| !actions.is_empty())
 6396    }
 6397
 6398    fn render_inline_code_actions(
 6399        &self,
 6400        icon_size: ui::IconSize,
 6401        display_row: DisplayRow,
 6402        is_active: bool,
 6403        cx: &mut Context<Self>,
 6404    ) -> AnyElement {
 6405        let show_tooltip = !self.context_menu_visible();
 6406        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6407            .icon_size(icon_size)
 6408            .shape(ui::IconButtonShape::Square)
 6409            .icon_color(ui::Color::Hidden)
 6410            .toggle_state(is_active)
 6411            .when(show_tooltip, |this| {
 6412                this.tooltip({
 6413                    let focus_handle = self.focus_handle.clone();
 6414                    move |window, cx| {
 6415                        Tooltip::for_action_in(
 6416                            "Toggle Code Actions",
 6417                            &ToggleCodeActions {
 6418                                deployed_from: None,
 6419                                quick_launch: false,
 6420                            },
 6421                            &focus_handle,
 6422                            window,
 6423                            cx,
 6424                        )
 6425                    }
 6426                })
 6427            })
 6428            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6429                window.focus(&editor.focus_handle(cx));
 6430                editor.toggle_code_actions(
 6431                    &crate::actions::ToggleCodeActions {
 6432                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6433                            display_row,
 6434                        )),
 6435                        quick_launch: false,
 6436                    },
 6437                    window,
 6438                    cx,
 6439                );
 6440            }))
 6441            .into_any_element()
 6442    }
 6443
 6444    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6445        &self.context_menu
 6446    }
 6447
 6448    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6449        let newest_selection = self.selections.newest_anchor().clone();
 6450        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6451        let buffer = self.buffer.read(cx);
 6452        if newest_selection.head().diff_base_anchor.is_some() {
 6453            return None;
 6454        }
 6455        let (start_buffer, start) =
 6456            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6457        let (end_buffer, end) =
 6458            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6459        if start_buffer != end_buffer {
 6460            return None;
 6461        }
 6462
 6463        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6464            cx.background_executor()
 6465                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6466                .await;
 6467
 6468            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6469                let providers = this.code_action_providers.clone();
 6470                let tasks = this
 6471                    .code_action_providers
 6472                    .iter()
 6473                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6474                    .collect::<Vec<_>>();
 6475                (providers, tasks)
 6476            })?;
 6477
 6478            let mut actions = Vec::new();
 6479            for (provider, provider_actions) in
 6480                providers.into_iter().zip(future::join_all(tasks).await)
 6481            {
 6482                if let Some(provider_actions) = provider_actions.log_err() {
 6483                    actions.extend(provider_actions.into_iter().map(|action| {
 6484                        AvailableCodeAction {
 6485                            excerpt_id: newest_selection.start.excerpt_id,
 6486                            action,
 6487                            provider: provider.clone(),
 6488                        }
 6489                    }));
 6490                }
 6491            }
 6492
 6493            this.update(cx, |this, cx| {
 6494                this.available_code_actions = if actions.is_empty() {
 6495                    None
 6496                } else {
 6497                    Some((
 6498                        Location {
 6499                            buffer: start_buffer,
 6500                            range: start..end,
 6501                        },
 6502                        actions.into(),
 6503                    ))
 6504                };
 6505                cx.notify();
 6506            })
 6507        }));
 6508        None
 6509    }
 6510
 6511    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6512        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6513            self.show_git_blame_inline = false;
 6514
 6515            self.show_git_blame_inline_delay_task =
 6516                Some(cx.spawn_in(window, async move |this, cx| {
 6517                    cx.background_executor().timer(delay).await;
 6518
 6519                    this.update(cx, |this, cx| {
 6520                        this.show_git_blame_inline = true;
 6521                        cx.notify();
 6522                    })
 6523                    .log_err();
 6524                }));
 6525        }
 6526    }
 6527
 6528    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6529        let snapshot = self.snapshot(window, cx);
 6530        let cursor = self.selections.newest::<Point>(cx).head();
 6531        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6532        else {
 6533            return;
 6534        };
 6535
 6536        let Some(blame) = self.blame.as_ref() else {
 6537            return;
 6538        };
 6539
 6540        let row_info = RowInfo {
 6541            buffer_id: Some(buffer.remote_id()),
 6542            buffer_row: Some(point.row),
 6543            ..Default::default()
 6544        };
 6545        let Some(blame_entry) = blame
 6546            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6547            .flatten()
 6548        else {
 6549            return;
 6550        };
 6551
 6552        let anchor = self.selections.newest_anchor().head();
 6553        let position = self.to_pixel_point(anchor, &snapshot, window);
 6554        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6555            self.show_blame_popover(&blame_entry, position + last_bounds.origin, true, cx);
 6556        };
 6557    }
 6558
 6559    fn show_blame_popover(
 6560        &mut self,
 6561        blame_entry: &BlameEntry,
 6562        position: gpui::Point<Pixels>,
 6563        ignore_timeout: bool,
 6564        cx: &mut Context<Self>,
 6565    ) {
 6566        if let Some(state) = &mut self.inline_blame_popover {
 6567            state.hide_task.take();
 6568        } else {
 6569            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6570            let blame_entry = blame_entry.clone();
 6571            let show_task = cx.spawn(async move |editor, cx| {
 6572                if !ignore_timeout {
 6573                    cx.background_executor()
 6574                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6575                        .await;
 6576                }
 6577                editor
 6578                    .update(cx, |editor, cx| {
 6579                        editor.inline_blame_popover_show_task.take();
 6580                        let Some(blame) = editor.blame.as_ref() else {
 6581                            return;
 6582                        };
 6583                        let blame = blame.read(cx);
 6584                        let details = blame.details_for_entry(&blame_entry);
 6585                        let markdown = cx.new(|cx| {
 6586                            Markdown::new(
 6587                                details
 6588                                    .as_ref()
 6589                                    .map(|message| message.message.clone())
 6590                                    .unwrap_or_default(),
 6591                                None,
 6592                                None,
 6593                                cx,
 6594                            )
 6595                        });
 6596                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6597                            position,
 6598                            hide_task: None,
 6599                            popover_bounds: None,
 6600                            popover_state: InlineBlamePopoverState {
 6601                                scroll_handle: ScrollHandle::new(),
 6602                                commit_message: details,
 6603                                markdown,
 6604                            },
 6605                            keyboard_grace: ignore_timeout,
 6606                        });
 6607                        cx.notify();
 6608                    })
 6609                    .ok();
 6610            });
 6611            self.inline_blame_popover_show_task = Some(show_task);
 6612        }
 6613    }
 6614
 6615    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6616        self.inline_blame_popover_show_task.take();
 6617        if let Some(state) = &mut self.inline_blame_popover {
 6618            let hide_task = cx.spawn(async move |editor, cx| {
 6619                cx.background_executor()
 6620                    .timer(std::time::Duration::from_millis(100))
 6621                    .await;
 6622                editor
 6623                    .update(cx, |editor, cx| {
 6624                        editor.inline_blame_popover.take();
 6625                        cx.notify();
 6626                    })
 6627                    .ok();
 6628            });
 6629            state.hide_task = Some(hide_task);
 6630        }
 6631    }
 6632
 6633    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6634        if self.pending_rename.is_some() {
 6635            return None;
 6636        }
 6637
 6638        let provider = self.semantics_provider.clone()?;
 6639        let buffer = self.buffer.read(cx);
 6640        let newest_selection = self.selections.newest_anchor().clone();
 6641        let cursor_position = newest_selection.head();
 6642        let (cursor_buffer, cursor_buffer_position) =
 6643            buffer.text_anchor_for_position(cursor_position, cx)?;
 6644        let (tail_buffer, tail_buffer_position) =
 6645            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6646        if cursor_buffer != tail_buffer {
 6647            return None;
 6648        }
 6649
 6650        let snapshot = cursor_buffer.read(cx).snapshot();
 6651        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6652        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6653        if start_word_range != end_word_range {
 6654            self.document_highlights_task.take();
 6655            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6656            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6657            return None;
 6658        }
 6659
 6660        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6661        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6662            cx.background_executor()
 6663                .timer(Duration::from_millis(debounce))
 6664                .await;
 6665
 6666            let highlights = if let Some(highlights) = cx
 6667                .update(|cx| {
 6668                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6669                })
 6670                .ok()
 6671                .flatten()
 6672            {
 6673                highlights.await.log_err()
 6674            } else {
 6675                None
 6676            };
 6677
 6678            if let Some(highlights) = highlights {
 6679                this.update(cx, |this, cx| {
 6680                    if this.pending_rename.is_some() {
 6681                        return;
 6682                    }
 6683
 6684                    let buffer_id = cursor_position.buffer_id;
 6685                    let buffer = this.buffer.read(cx);
 6686                    if !buffer
 6687                        .text_anchor_for_position(cursor_position, cx)
 6688                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6689                    {
 6690                        return;
 6691                    }
 6692
 6693                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6694                    let mut write_ranges = Vec::new();
 6695                    let mut read_ranges = Vec::new();
 6696                    for highlight in highlights {
 6697                        for (excerpt_id, excerpt_range) in
 6698                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6699                        {
 6700                            let start = highlight
 6701                                .range
 6702                                .start
 6703                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6704                            let end = highlight
 6705                                .range
 6706                                .end
 6707                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6708                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6709                                continue;
 6710                            }
 6711
 6712                            let range = Anchor {
 6713                                buffer_id,
 6714                                excerpt_id,
 6715                                text_anchor: start,
 6716                                diff_base_anchor: None,
 6717                            }..Anchor {
 6718                                buffer_id,
 6719                                excerpt_id,
 6720                                text_anchor: end,
 6721                                diff_base_anchor: None,
 6722                            };
 6723                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6724                                write_ranges.push(range);
 6725                            } else {
 6726                                read_ranges.push(range);
 6727                            }
 6728                        }
 6729                    }
 6730
 6731                    this.highlight_background::<DocumentHighlightRead>(
 6732                        &read_ranges,
 6733                        |theme| theme.colors().editor_document_highlight_read_background,
 6734                        cx,
 6735                    );
 6736                    this.highlight_background::<DocumentHighlightWrite>(
 6737                        &write_ranges,
 6738                        |theme| theme.colors().editor_document_highlight_write_background,
 6739                        cx,
 6740                    );
 6741                    cx.notify();
 6742                })
 6743                .log_err();
 6744            }
 6745        }));
 6746        None
 6747    }
 6748
 6749    fn prepare_highlight_query_from_selection(
 6750        &mut self,
 6751        cx: &mut Context<Editor>,
 6752    ) -> Option<(String, Range<Anchor>)> {
 6753        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6754            return None;
 6755        }
 6756        if !EditorSettings::get_global(cx).selection_highlight {
 6757            return None;
 6758        }
 6759        if self.selections.count() != 1 || self.selections.line_mode {
 6760            return None;
 6761        }
 6762        let selection = self.selections.newest::<Point>(cx);
 6763        if selection.is_empty() || selection.start.row != selection.end.row {
 6764            return None;
 6765        }
 6766        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6767        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6768        let query = multi_buffer_snapshot
 6769            .text_for_range(selection_anchor_range.clone())
 6770            .collect::<String>();
 6771        if query.trim().is_empty() {
 6772            return None;
 6773        }
 6774        Some((query, selection_anchor_range))
 6775    }
 6776
 6777    fn update_selection_occurrence_highlights(
 6778        &mut self,
 6779        query_text: String,
 6780        query_range: Range<Anchor>,
 6781        multi_buffer_range_to_query: Range<Point>,
 6782        use_debounce: bool,
 6783        window: &mut Window,
 6784        cx: &mut Context<Editor>,
 6785    ) -> Task<()> {
 6786        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6787        cx.spawn_in(window, async move |editor, cx| {
 6788            if use_debounce {
 6789                cx.background_executor()
 6790                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6791                    .await;
 6792            }
 6793            let match_task = cx.background_spawn(async move {
 6794                let buffer_ranges = multi_buffer_snapshot
 6795                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6796                    .into_iter()
 6797                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6798                let mut match_ranges = Vec::new();
 6799                let Ok(regex) = project::search::SearchQuery::text(
 6800                    query_text.clone(),
 6801                    false,
 6802                    false,
 6803                    false,
 6804                    Default::default(),
 6805                    Default::default(),
 6806                    false,
 6807                    None,
 6808                ) else {
 6809                    return Vec::default();
 6810                };
 6811                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6812                    match_ranges.extend(
 6813                        regex
 6814                            .search(&buffer_snapshot, Some(search_range.clone()))
 6815                            .await
 6816                            .into_iter()
 6817                            .filter_map(|match_range| {
 6818                                let match_start = buffer_snapshot
 6819                                    .anchor_after(search_range.start + match_range.start);
 6820                                let match_end = buffer_snapshot
 6821                                    .anchor_before(search_range.start + match_range.end);
 6822                                let match_anchor_range = Anchor::range_in_buffer(
 6823                                    excerpt_id,
 6824                                    buffer_snapshot.remote_id(),
 6825                                    match_start..match_end,
 6826                                );
 6827                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6828                            }),
 6829                    );
 6830                }
 6831                match_ranges
 6832            });
 6833            let match_ranges = match_task.await;
 6834            editor
 6835                .update_in(cx, |editor, _, cx| {
 6836                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6837                    if !match_ranges.is_empty() {
 6838                        editor.highlight_background::<SelectedTextHighlight>(
 6839                            &match_ranges,
 6840                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6841                            cx,
 6842                        )
 6843                    }
 6844                })
 6845                .log_err();
 6846        })
 6847    }
 6848
 6849    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6850        struct NewlineFold;
 6851        let type_id = std::any::TypeId::of::<NewlineFold>();
 6852        if !self.mode.is_single_line() {
 6853            return;
 6854        }
 6855        let snapshot = self.snapshot(window, cx);
 6856        if snapshot.buffer_snapshot.max_point().row == 0 {
 6857            return;
 6858        }
 6859        let task = cx.background_spawn(async move {
 6860            let new_newlines = snapshot
 6861                .buffer_chars_at(0)
 6862                .filter_map(|(c, i)| {
 6863                    if c == '\n' {
 6864                        Some(
 6865                            snapshot.buffer_snapshot.anchor_after(i)
 6866                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6867                        )
 6868                    } else {
 6869                        None
 6870                    }
 6871                })
 6872                .collect::<Vec<_>>();
 6873            let existing_newlines = snapshot
 6874                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6875                .filter_map(|fold| {
 6876                    if fold.placeholder.type_tag == Some(type_id) {
 6877                        Some(fold.range.start..fold.range.end)
 6878                    } else {
 6879                        None
 6880                    }
 6881                })
 6882                .collect::<Vec<_>>();
 6883
 6884            (new_newlines, existing_newlines)
 6885        });
 6886        self.folding_newlines = cx.spawn(async move |this, cx| {
 6887            let (new_newlines, existing_newlines) = task.await;
 6888            if new_newlines == existing_newlines {
 6889                return;
 6890            }
 6891            let placeholder = FoldPlaceholder {
 6892                render: Arc::new(move |_, _, cx| {
 6893                    div()
 6894                        .bg(cx.theme().status().hint_background)
 6895                        .border_b_1()
 6896                        .size_full()
 6897                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6898                        .border_color(cx.theme().status().hint)
 6899                        .child("\\n")
 6900                        .into_any()
 6901                }),
 6902                constrain_width: false,
 6903                merge_adjacent: false,
 6904                type_tag: Some(type_id),
 6905            };
 6906            let creases = new_newlines
 6907                .into_iter()
 6908                .map(|range| Crease::simple(range, placeholder.clone()))
 6909                .collect();
 6910            this.update(cx, |this, cx| {
 6911                this.display_map.update(cx, |display_map, cx| {
 6912                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6913                    display_map.fold(creases, cx);
 6914                });
 6915            })
 6916            .ok();
 6917        });
 6918    }
 6919
 6920    fn refresh_selected_text_highlights(
 6921        &mut self,
 6922        on_buffer_edit: bool,
 6923        window: &mut Window,
 6924        cx: &mut Context<Editor>,
 6925    ) {
 6926        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6927        else {
 6928            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6929            self.quick_selection_highlight_task.take();
 6930            self.debounced_selection_highlight_task.take();
 6931            return;
 6932        };
 6933        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6934        if on_buffer_edit
 6935            || self
 6936                .quick_selection_highlight_task
 6937                .as_ref()
 6938                .map_or(true, |(prev_anchor_range, _)| {
 6939                    prev_anchor_range != &query_range
 6940                })
 6941        {
 6942            let multi_buffer_visible_start = self
 6943                .scroll_manager
 6944                .anchor()
 6945                .anchor
 6946                .to_point(&multi_buffer_snapshot);
 6947            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6948                multi_buffer_visible_start
 6949                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6950                Bias::Left,
 6951            );
 6952            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6953            self.quick_selection_highlight_task = Some((
 6954                query_range.clone(),
 6955                self.update_selection_occurrence_highlights(
 6956                    query_text.clone(),
 6957                    query_range.clone(),
 6958                    multi_buffer_visible_range,
 6959                    false,
 6960                    window,
 6961                    cx,
 6962                ),
 6963            ));
 6964        }
 6965        if on_buffer_edit
 6966            || self
 6967                .debounced_selection_highlight_task
 6968                .as_ref()
 6969                .map_or(true, |(prev_anchor_range, _)| {
 6970                    prev_anchor_range != &query_range
 6971                })
 6972        {
 6973            let multi_buffer_start = multi_buffer_snapshot
 6974                .anchor_before(0)
 6975                .to_point(&multi_buffer_snapshot);
 6976            let multi_buffer_end = multi_buffer_snapshot
 6977                .anchor_after(multi_buffer_snapshot.len())
 6978                .to_point(&multi_buffer_snapshot);
 6979            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6980            self.debounced_selection_highlight_task = Some((
 6981                query_range.clone(),
 6982                self.update_selection_occurrence_highlights(
 6983                    query_text,
 6984                    query_range,
 6985                    multi_buffer_full_range,
 6986                    true,
 6987                    window,
 6988                    cx,
 6989                ),
 6990            ));
 6991        }
 6992    }
 6993
 6994    pub fn refresh_edit_prediction(
 6995        &mut self,
 6996        debounce: bool,
 6997        user_requested: bool,
 6998        window: &mut Window,
 6999        cx: &mut Context<Self>,
 7000    ) -> Option<()> {
 7001        if DisableAiSettings::get_global(cx).disable_ai {
 7002            return None;
 7003        }
 7004
 7005        let provider = self.edit_prediction_provider()?;
 7006        let cursor = self.selections.newest_anchor().head();
 7007        let (buffer, cursor_buffer_position) =
 7008            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7009
 7010        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7011            self.discard_edit_prediction(false, cx);
 7012            return None;
 7013        }
 7014
 7015        if !user_requested
 7016            && (!self.should_show_edit_predictions()
 7017                || !self.is_focused(window)
 7018                || buffer.read(cx).is_empty())
 7019        {
 7020            self.discard_edit_prediction(false, cx);
 7021            return None;
 7022        }
 7023
 7024        self.update_visible_edit_prediction(window, cx);
 7025        provider.refresh(
 7026            self.project.clone(),
 7027            buffer,
 7028            cursor_buffer_position,
 7029            debounce,
 7030            cx,
 7031        );
 7032        Some(())
 7033    }
 7034
 7035    fn show_edit_predictions_in_menu(&self) -> bool {
 7036        match self.edit_prediction_settings {
 7037            EditPredictionSettings::Disabled => false,
 7038            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7039        }
 7040    }
 7041
 7042    pub fn edit_predictions_enabled(&self) -> bool {
 7043        match self.edit_prediction_settings {
 7044            EditPredictionSettings::Disabled => false,
 7045            EditPredictionSettings::Enabled { .. } => true,
 7046        }
 7047    }
 7048
 7049    fn edit_prediction_requires_modifier(&self) -> bool {
 7050        match self.edit_prediction_settings {
 7051            EditPredictionSettings::Disabled => false,
 7052            EditPredictionSettings::Enabled {
 7053                preview_requires_modifier,
 7054                ..
 7055            } => preview_requires_modifier,
 7056        }
 7057    }
 7058
 7059    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7060        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7061            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7062            self.discard_edit_prediction(false, cx);
 7063        } else {
 7064            let selection = self.selections.newest_anchor();
 7065            let cursor = selection.head();
 7066
 7067            if let Some((buffer, cursor_buffer_position)) =
 7068                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7069            {
 7070                self.edit_prediction_settings =
 7071                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7072            }
 7073        }
 7074    }
 7075
 7076    fn edit_prediction_settings_at_position(
 7077        &self,
 7078        buffer: &Entity<Buffer>,
 7079        buffer_position: language::Anchor,
 7080        cx: &App,
 7081    ) -> EditPredictionSettings {
 7082        if !self.mode.is_full()
 7083            || !self.show_edit_predictions_override.unwrap_or(true)
 7084            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7085        {
 7086            return EditPredictionSettings::Disabled;
 7087        }
 7088
 7089        let buffer = buffer.read(cx);
 7090
 7091        let file = buffer.file();
 7092
 7093        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7094            return EditPredictionSettings::Disabled;
 7095        };
 7096
 7097        let by_provider = matches!(
 7098            self.menu_edit_predictions_policy,
 7099            MenuEditPredictionsPolicy::ByProvider
 7100        );
 7101
 7102        let show_in_menu = by_provider
 7103            && self
 7104                .edit_prediction_provider
 7105                .as_ref()
 7106                .map_or(false, |provider| {
 7107                    provider.provider.show_completions_in_menu()
 7108                });
 7109
 7110        let preview_requires_modifier =
 7111            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7112
 7113        EditPredictionSettings::Enabled {
 7114            show_in_menu,
 7115            preview_requires_modifier,
 7116        }
 7117    }
 7118
 7119    fn should_show_edit_predictions(&self) -> bool {
 7120        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7121    }
 7122
 7123    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7124        matches!(
 7125            self.edit_prediction_preview,
 7126            EditPredictionPreview::Active { .. }
 7127        )
 7128    }
 7129
 7130    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7131        let cursor = self.selections.newest_anchor().head();
 7132        if let Some((buffer, cursor_position)) =
 7133            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7134        {
 7135            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7136        } else {
 7137            false
 7138        }
 7139    }
 7140
 7141    pub fn supports_minimap(&self, cx: &App) -> bool {
 7142        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7143    }
 7144
 7145    fn edit_predictions_enabled_in_buffer(
 7146        &self,
 7147        buffer: &Entity<Buffer>,
 7148        buffer_position: language::Anchor,
 7149        cx: &App,
 7150    ) -> bool {
 7151        maybe!({
 7152            if self.read_only(cx) {
 7153                return Some(false);
 7154            }
 7155            let provider = self.edit_prediction_provider()?;
 7156            if !provider.is_enabled(&buffer, buffer_position, cx) {
 7157                return Some(false);
 7158            }
 7159            let buffer = buffer.read(cx);
 7160            let Some(file) = buffer.file() else {
 7161                return Some(true);
 7162            };
 7163            let settings = all_language_settings(Some(file), cx);
 7164            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7165        })
 7166        .unwrap_or(false)
 7167    }
 7168
 7169    fn cycle_edit_prediction(
 7170        &mut self,
 7171        direction: Direction,
 7172        window: &mut Window,
 7173        cx: &mut Context<Self>,
 7174    ) -> Option<()> {
 7175        let provider = self.edit_prediction_provider()?;
 7176        let cursor = self.selections.newest_anchor().head();
 7177        let (buffer, cursor_buffer_position) =
 7178            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7179        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7180            return None;
 7181        }
 7182
 7183        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7184        self.update_visible_edit_prediction(window, cx);
 7185
 7186        Some(())
 7187    }
 7188
 7189    pub fn show_edit_prediction(
 7190        &mut self,
 7191        _: &ShowEditPrediction,
 7192        window: &mut Window,
 7193        cx: &mut Context<Self>,
 7194    ) {
 7195        if !self.has_active_edit_prediction() {
 7196            self.refresh_edit_prediction(false, true, window, cx);
 7197            return;
 7198        }
 7199
 7200        self.update_visible_edit_prediction(window, cx);
 7201    }
 7202
 7203    pub fn display_cursor_names(
 7204        &mut self,
 7205        _: &DisplayCursorNames,
 7206        window: &mut Window,
 7207        cx: &mut Context<Self>,
 7208    ) {
 7209        self.show_cursor_names(window, cx);
 7210    }
 7211
 7212    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7213        self.show_cursor_names = true;
 7214        cx.notify();
 7215        cx.spawn_in(window, async move |this, cx| {
 7216            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7217            this.update(cx, |this, cx| {
 7218                this.show_cursor_names = false;
 7219                cx.notify()
 7220            })
 7221            .ok()
 7222        })
 7223        .detach();
 7224    }
 7225
 7226    pub fn next_edit_prediction(
 7227        &mut self,
 7228        _: &NextEditPrediction,
 7229        window: &mut Window,
 7230        cx: &mut Context<Self>,
 7231    ) {
 7232        if self.has_active_edit_prediction() {
 7233            self.cycle_edit_prediction(Direction::Next, window, cx);
 7234        } else {
 7235            let is_copilot_disabled = self
 7236                .refresh_edit_prediction(false, true, window, cx)
 7237                .is_none();
 7238            if is_copilot_disabled {
 7239                cx.propagate();
 7240            }
 7241        }
 7242    }
 7243
 7244    pub fn previous_edit_prediction(
 7245        &mut self,
 7246        _: &PreviousEditPrediction,
 7247        window: &mut Window,
 7248        cx: &mut Context<Self>,
 7249    ) {
 7250        if self.has_active_edit_prediction() {
 7251            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7252        } else {
 7253            let is_copilot_disabled = self
 7254                .refresh_edit_prediction(false, true, window, cx)
 7255                .is_none();
 7256            if is_copilot_disabled {
 7257                cx.propagate();
 7258            }
 7259        }
 7260    }
 7261
 7262    pub fn accept_edit_prediction(
 7263        &mut self,
 7264        _: &AcceptEditPrediction,
 7265        window: &mut Window,
 7266        cx: &mut Context<Self>,
 7267    ) {
 7268        if self.show_edit_predictions_in_menu() {
 7269            self.hide_context_menu(window, cx);
 7270        }
 7271
 7272        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7273            return;
 7274        };
 7275
 7276        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7277
 7278        match &active_edit_prediction.completion {
 7279            EditPrediction::Move { target, .. } => {
 7280                let target = *target;
 7281
 7282                if let Some(position_map) = &self.last_position_map {
 7283                    if position_map
 7284                        .visible_row_range
 7285                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7286                        || !self.edit_prediction_requires_modifier()
 7287                    {
 7288                        self.unfold_ranges(&[target..target], true, false, cx);
 7289                        // Note that this is also done in vim's handler of the Tab action.
 7290                        self.change_selections(
 7291                            SelectionEffects::scroll(Autoscroll::newest()),
 7292                            window,
 7293                            cx,
 7294                            |selections| {
 7295                                selections.select_anchor_ranges([target..target]);
 7296                            },
 7297                        );
 7298                        self.clear_row_highlights::<EditPredictionPreview>();
 7299
 7300                        self.edit_prediction_preview
 7301                            .set_previous_scroll_position(None);
 7302                    } else {
 7303                        self.edit_prediction_preview
 7304                            .set_previous_scroll_position(Some(
 7305                                position_map.snapshot.scroll_anchor,
 7306                            ));
 7307
 7308                        self.highlight_rows::<EditPredictionPreview>(
 7309                            target..target,
 7310                            cx.theme().colors().editor_highlighted_line_background,
 7311                            RowHighlightOptions {
 7312                                autoscroll: true,
 7313                                ..Default::default()
 7314                            },
 7315                            cx,
 7316                        );
 7317                        self.request_autoscroll(Autoscroll::fit(), cx);
 7318                    }
 7319                }
 7320            }
 7321            EditPrediction::Edit { edits, .. } => {
 7322                if let Some(provider) = self.edit_prediction_provider() {
 7323                    provider.accept(cx);
 7324                }
 7325
 7326                // Store the transaction ID and selections before applying the edit
 7327                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7328
 7329                let snapshot = self.buffer.read(cx).snapshot(cx);
 7330                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7331
 7332                self.buffer.update(cx, |buffer, cx| {
 7333                    buffer.edit(edits.iter().cloned(), None, cx)
 7334                });
 7335
 7336                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7337                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7338                });
 7339
 7340                let selections = self.selections.disjoint_anchors();
 7341                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7342                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7343                    if has_new_transaction {
 7344                        self.selection_history
 7345                            .insert_transaction(transaction_id_now, selections);
 7346                    }
 7347                }
 7348
 7349                self.update_visible_edit_prediction(window, cx);
 7350                if self.active_edit_prediction.is_none() {
 7351                    self.refresh_edit_prediction(true, true, window, cx);
 7352                }
 7353
 7354                cx.notify();
 7355            }
 7356        }
 7357
 7358        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7359    }
 7360
 7361    pub fn accept_partial_edit_prediction(
 7362        &mut self,
 7363        _: &AcceptPartialEditPrediction,
 7364        window: &mut Window,
 7365        cx: &mut Context<Self>,
 7366    ) {
 7367        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7368            return;
 7369        };
 7370        if self.selections.count() != 1 {
 7371            return;
 7372        }
 7373
 7374        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7375
 7376        match &active_edit_prediction.completion {
 7377            EditPrediction::Move { target, .. } => {
 7378                let target = *target;
 7379                self.change_selections(
 7380                    SelectionEffects::scroll(Autoscroll::newest()),
 7381                    window,
 7382                    cx,
 7383                    |selections| {
 7384                        selections.select_anchor_ranges([target..target]);
 7385                    },
 7386                );
 7387            }
 7388            EditPrediction::Edit { edits, .. } => {
 7389                // Find an insertion that starts at the cursor position.
 7390                let snapshot = self.buffer.read(cx).snapshot(cx);
 7391                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7392                let insertion = edits.iter().find_map(|(range, text)| {
 7393                    let range = range.to_offset(&snapshot);
 7394                    if range.is_empty() && range.start == cursor_offset {
 7395                        Some(text)
 7396                    } else {
 7397                        None
 7398                    }
 7399                });
 7400
 7401                if let Some(text) = insertion {
 7402                    let mut partial_completion = text
 7403                        .chars()
 7404                        .by_ref()
 7405                        .take_while(|c| c.is_alphabetic())
 7406                        .collect::<String>();
 7407                    if partial_completion.is_empty() {
 7408                        partial_completion = text
 7409                            .chars()
 7410                            .by_ref()
 7411                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7412                            .collect::<String>();
 7413                    }
 7414
 7415                    cx.emit(EditorEvent::InputHandled {
 7416                        utf16_range_to_replace: None,
 7417                        text: partial_completion.clone().into(),
 7418                    });
 7419
 7420                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7421
 7422                    self.refresh_edit_prediction(true, true, window, cx);
 7423                    cx.notify();
 7424                } else {
 7425                    self.accept_edit_prediction(&Default::default(), window, cx);
 7426                }
 7427            }
 7428        }
 7429    }
 7430
 7431    fn discard_edit_prediction(
 7432        &mut self,
 7433        should_report_edit_prediction_event: bool,
 7434        cx: &mut Context<Self>,
 7435    ) -> bool {
 7436        if should_report_edit_prediction_event {
 7437            let completion_id = self
 7438                .active_edit_prediction
 7439                .as_ref()
 7440                .and_then(|active_completion| active_completion.completion_id.clone());
 7441
 7442            self.report_edit_prediction_event(completion_id, false, cx);
 7443        }
 7444
 7445        if let Some(provider) = self.edit_prediction_provider() {
 7446            provider.discard(cx);
 7447        }
 7448
 7449        self.take_active_edit_prediction(cx)
 7450    }
 7451
 7452    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7453        let Some(provider) = self.edit_prediction_provider() else {
 7454            return;
 7455        };
 7456
 7457        let Some((_, buffer, _)) = self
 7458            .buffer
 7459            .read(cx)
 7460            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7461        else {
 7462            return;
 7463        };
 7464
 7465        let extension = buffer
 7466            .read(cx)
 7467            .file()
 7468            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7469
 7470        let event_type = match accepted {
 7471            true => "Edit Prediction Accepted",
 7472            false => "Edit Prediction Discarded",
 7473        };
 7474        telemetry::event!(
 7475            event_type,
 7476            provider = provider.name(),
 7477            prediction_id = id,
 7478            suggestion_accepted = accepted,
 7479            file_extension = extension,
 7480        );
 7481    }
 7482
 7483    pub fn has_active_edit_prediction(&self) -> bool {
 7484        self.active_edit_prediction.is_some()
 7485    }
 7486
 7487    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7488        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7489            return false;
 7490        };
 7491
 7492        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7493        self.clear_highlights::<EditPredictionHighlight>(cx);
 7494        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7495        true
 7496    }
 7497
 7498    /// Returns true when we're displaying the edit prediction popover below the cursor
 7499    /// like we are not previewing and the LSP autocomplete menu is visible
 7500    /// or we are in `when_holding_modifier` mode.
 7501    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7502        if self.edit_prediction_preview_is_active()
 7503            || !self.show_edit_predictions_in_menu()
 7504            || !self.edit_predictions_enabled()
 7505        {
 7506            return false;
 7507        }
 7508
 7509        if self.has_visible_completions_menu() {
 7510            return true;
 7511        }
 7512
 7513        has_completion && self.edit_prediction_requires_modifier()
 7514    }
 7515
 7516    fn handle_modifiers_changed(
 7517        &mut self,
 7518        modifiers: Modifiers,
 7519        position_map: &PositionMap,
 7520        window: &mut Window,
 7521        cx: &mut Context<Self>,
 7522    ) {
 7523        if self.show_edit_predictions_in_menu() {
 7524            self.update_edit_prediction_preview(&modifiers, window, cx);
 7525        }
 7526
 7527        self.update_selection_mode(&modifiers, position_map, window, cx);
 7528
 7529        let mouse_position = window.mouse_position();
 7530        if !position_map.text_hitbox.is_hovered(window) {
 7531            return;
 7532        }
 7533
 7534        self.update_hovered_link(
 7535            position_map.point_for_position(mouse_position),
 7536            &position_map.snapshot,
 7537            modifiers,
 7538            window,
 7539            cx,
 7540        )
 7541    }
 7542
 7543    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7544        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7545        if invert {
 7546            match multi_cursor_setting {
 7547                MultiCursorModifier::Alt => modifiers.alt,
 7548                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7549            }
 7550        } else {
 7551            match multi_cursor_setting {
 7552                MultiCursorModifier::Alt => modifiers.secondary(),
 7553                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7554            }
 7555        }
 7556    }
 7557
 7558    fn columnar_selection_mode(
 7559        modifiers: &Modifiers,
 7560        cx: &mut Context<Self>,
 7561    ) -> Option<ColumnarMode> {
 7562        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7563            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7564                Some(ColumnarMode::FromMouse)
 7565            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7566                Some(ColumnarMode::FromSelection)
 7567            } else {
 7568                None
 7569            }
 7570        } else {
 7571            None
 7572        }
 7573    }
 7574
 7575    fn update_selection_mode(
 7576        &mut self,
 7577        modifiers: &Modifiers,
 7578        position_map: &PositionMap,
 7579        window: &mut Window,
 7580        cx: &mut Context<Self>,
 7581    ) {
 7582        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7583            return;
 7584        };
 7585        if self.selections.pending.is_none() {
 7586            return;
 7587        }
 7588
 7589        let mouse_position = window.mouse_position();
 7590        let point_for_position = position_map.point_for_position(mouse_position);
 7591        let position = point_for_position.previous_valid;
 7592
 7593        self.select(
 7594            SelectPhase::BeginColumnar {
 7595                position,
 7596                reset: false,
 7597                mode,
 7598                goal_column: point_for_position.exact_unclipped.column(),
 7599            },
 7600            window,
 7601            cx,
 7602        );
 7603    }
 7604
 7605    fn update_edit_prediction_preview(
 7606        &mut self,
 7607        modifiers: &Modifiers,
 7608        window: &mut Window,
 7609        cx: &mut Context<Self>,
 7610    ) {
 7611        let mut modifiers_held = false;
 7612        if let Some(accept_keystroke) = self
 7613            .accept_edit_prediction_keybind(false, window, cx)
 7614            .keystroke()
 7615        {
 7616            modifiers_held = modifiers_held
 7617                || (&accept_keystroke.modifiers == modifiers
 7618                    && accept_keystroke.modifiers.modified());
 7619        };
 7620        if let Some(accept_partial_keystroke) = self
 7621            .accept_edit_prediction_keybind(true, window, cx)
 7622            .keystroke()
 7623        {
 7624            modifiers_held = modifiers_held
 7625                || (&accept_partial_keystroke.modifiers == modifiers
 7626                    && accept_partial_keystroke.modifiers.modified());
 7627        }
 7628
 7629        if modifiers_held {
 7630            if matches!(
 7631                self.edit_prediction_preview,
 7632                EditPredictionPreview::Inactive { .. }
 7633            ) {
 7634                self.edit_prediction_preview = EditPredictionPreview::Active {
 7635                    previous_scroll_position: None,
 7636                    since: Instant::now(),
 7637                };
 7638
 7639                self.update_visible_edit_prediction(window, cx);
 7640                cx.notify();
 7641            }
 7642        } else if let EditPredictionPreview::Active {
 7643            previous_scroll_position,
 7644            since,
 7645        } = self.edit_prediction_preview
 7646        {
 7647            if let (Some(previous_scroll_position), Some(position_map)) =
 7648                (previous_scroll_position, self.last_position_map.as_ref())
 7649            {
 7650                self.set_scroll_position(
 7651                    previous_scroll_position
 7652                        .scroll_position(&position_map.snapshot.display_snapshot),
 7653                    window,
 7654                    cx,
 7655                );
 7656            }
 7657
 7658            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7659                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7660            };
 7661            self.clear_row_highlights::<EditPredictionPreview>();
 7662            self.update_visible_edit_prediction(window, cx);
 7663            cx.notify();
 7664        }
 7665    }
 7666
 7667    fn update_visible_edit_prediction(
 7668        &mut self,
 7669        _window: &mut Window,
 7670        cx: &mut Context<Self>,
 7671    ) -> Option<()> {
 7672        if DisableAiSettings::get_global(cx).disable_ai {
 7673            return None;
 7674        }
 7675
 7676        let selection = self.selections.newest_anchor();
 7677        let cursor = selection.head();
 7678        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7679        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7680        let excerpt_id = cursor.excerpt_id;
 7681
 7682        let show_in_menu = self.show_edit_predictions_in_menu();
 7683        let completions_menu_has_precedence = !show_in_menu
 7684            && (self.context_menu.borrow().is_some()
 7685                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7686
 7687        if completions_menu_has_precedence
 7688            || !offset_selection.is_empty()
 7689            || self
 7690                .active_edit_prediction
 7691                .as_ref()
 7692                .map_or(false, |completion| {
 7693                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7694                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7695                    !invalidation_range.contains(&offset_selection.head())
 7696                })
 7697        {
 7698            self.discard_edit_prediction(false, cx);
 7699            return None;
 7700        }
 7701
 7702        self.take_active_edit_prediction(cx);
 7703        let Some(provider) = self.edit_prediction_provider() else {
 7704            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7705            return None;
 7706        };
 7707
 7708        let (buffer, cursor_buffer_position) =
 7709            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7710
 7711        self.edit_prediction_settings =
 7712            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7713
 7714        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7715
 7716        if self.edit_prediction_indent_conflict {
 7717            let cursor_point = cursor.to_point(&multibuffer);
 7718
 7719            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7720
 7721            if let Some((_, indent)) = indents.iter().next() {
 7722                if indent.len == cursor_point.column {
 7723                    self.edit_prediction_indent_conflict = false;
 7724                }
 7725            }
 7726        }
 7727
 7728        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7729        let edits = edit_prediction
 7730            .edits
 7731            .into_iter()
 7732            .flat_map(|(range, new_text)| {
 7733                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7734                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7735                Some((start..end, new_text))
 7736            })
 7737            .collect::<Vec<_>>();
 7738        if edits.is_empty() {
 7739            return None;
 7740        }
 7741
 7742        let first_edit_start = edits.first().unwrap().0.start;
 7743        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7744        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7745
 7746        let last_edit_end = edits.last().unwrap().0.end;
 7747        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7748        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7749
 7750        let cursor_row = cursor.to_point(&multibuffer).row;
 7751
 7752        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7753
 7754        let mut inlay_ids = Vec::new();
 7755        let invalidation_row_range;
 7756        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7757            Some(cursor_row..edit_end_row)
 7758        } else if cursor_row > edit_end_row {
 7759            Some(edit_start_row..cursor_row)
 7760        } else {
 7761            None
 7762        };
 7763        let supports_jump = self
 7764            .edit_prediction_provider
 7765            .as_ref()
 7766            .map(|provider| provider.provider.supports_jump_to_edit())
 7767            .unwrap_or(true);
 7768
 7769        let is_move = supports_jump
 7770            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7771        let completion = if is_move {
 7772            invalidation_row_range =
 7773                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7774            let target = first_edit_start;
 7775            EditPrediction::Move { target, snapshot }
 7776        } else {
 7777            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7778                && !self.edit_predictions_hidden_for_vim_mode;
 7779
 7780            if show_completions_in_buffer {
 7781                if edits
 7782                    .iter()
 7783                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7784                {
 7785                    let mut inlays = Vec::new();
 7786                    for (range, new_text) in &edits {
 7787                        let inlay = Inlay::edit_prediction(
 7788                            post_inc(&mut self.next_inlay_id),
 7789                            range.start,
 7790                            new_text.as_str(),
 7791                        );
 7792                        inlay_ids.push(inlay.id);
 7793                        inlays.push(inlay);
 7794                    }
 7795
 7796                    self.splice_inlays(&[], inlays, cx);
 7797                } else {
 7798                    let background_color = cx.theme().status().deleted_background;
 7799                    self.highlight_text::<EditPredictionHighlight>(
 7800                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7801                        HighlightStyle {
 7802                            background_color: Some(background_color),
 7803                            ..Default::default()
 7804                        },
 7805                        cx,
 7806                    );
 7807                }
 7808            }
 7809
 7810            invalidation_row_range = edit_start_row..edit_end_row;
 7811
 7812            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7813                if provider.show_tab_accept_marker() {
 7814                    EditDisplayMode::TabAccept
 7815                } else {
 7816                    EditDisplayMode::Inline
 7817                }
 7818            } else {
 7819                EditDisplayMode::DiffPopover
 7820            };
 7821
 7822            EditPrediction::Edit {
 7823                edits,
 7824                edit_preview: edit_prediction.edit_preview,
 7825                display_mode,
 7826                snapshot,
 7827            }
 7828        };
 7829
 7830        let invalidation_range = multibuffer
 7831            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7832            ..multibuffer.anchor_after(Point::new(
 7833                invalidation_row_range.end,
 7834                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7835            ));
 7836
 7837        self.stale_edit_prediction_in_menu = None;
 7838        self.active_edit_prediction = Some(EditPredictionState {
 7839            inlay_ids,
 7840            completion,
 7841            completion_id: edit_prediction.id,
 7842            invalidation_range,
 7843        });
 7844
 7845        cx.notify();
 7846
 7847        Some(())
 7848    }
 7849
 7850    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7851        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7852    }
 7853
 7854    fn clear_tasks(&mut self) {
 7855        self.tasks.clear()
 7856    }
 7857
 7858    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7859        if self.tasks.insert(key, value).is_some() {
 7860            // This case should hopefully be rare, but just in case...
 7861            log::error!(
 7862                "multiple different run targets found on a single line, only the last target will be rendered"
 7863            )
 7864        }
 7865    }
 7866
 7867    /// Get all display points of breakpoints that will be rendered within editor
 7868    ///
 7869    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7870    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7871    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7872    fn active_breakpoints(
 7873        &self,
 7874        range: Range<DisplayRow>,
 7875        window: &mut Window,
 7876        cx: &mut Context<Self>,
 7877    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7878        let mut breakpoint_display_points = HashMap::default();
 7879
 7880        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7881            return breakpoint_display_points;
 7882        };
 7883
 7884        let snapshot = self.snapshot(window, cx);
 7885
 7886        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7887        let Some(project) = self.project.as_ref() else {
 7888            return breakpoint_display_points;
 7889        };
 7890
 7891        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7892            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7893
 7894        for (buffer_snapshot, range, excerpt_id) in
 7895            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7896        {
 7897            let Some(buffer) = project
 7898                .read(cx)
 7899                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7900            else {
 7901                continue;
 7902            };
 7903            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7904                &buffer,
 7905                Some(
 7906                    buffer_snapshot.anchor_before(range.start)
 7907                        ..buffer_snapshot.anchor_after(range.end),
 7908                ),
 7909                buffer_snapshot,
 7910                cx,
 7911            );
 7912            for (breakpoint, state) in breakpoints {
 7913                let multi_buffer_anchor =
 7914                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7915                let position = multi_buffer_anchor
 7916                    .to_point(&multi_buffer_snapshot)
 7917                    .to_display_point(&snapshot);
 7918
 7919                breakpoint_display_points.insert(
 7920                    position.row(),
 7921                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7922                );
 7923            }
 7924        }
 7925
 7926        breakpoint_display_points
 7927    }
 7928
 7929    fn breakpoint_context_menu(
 7930        &self,
 7931        anchor: Anchor,
 7932        window: &mut Window,
 7933        cx: &mut Context<Self>,
 7934    ) -> Entity<ui::ContextMenu> {
 7935        let weak_editor = cx.weak_entity();
 7936        let focus_handle = self.focus_handle(cx);
 7937
 7938        let row = self
 7939            .buffer
 7940            .read(cx)
 7941            .snapshot(cx)
 7942            .summary_for_anchor::<Point>(&anchor)
 7943            .row;
 7944
 7945        let breakpoint = self
 7946            .breakpoint_at_row(row, window, cx)
 7947            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7948
 7949        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7950            "Edit Log Breakpoint"
 7951        } else {
 7952            "Set Log Breakpoint"
 7953        };
 7954
 7955        let condition_breakpoint_msg = if breakpoint
 7956            .as_ref()
 7957            .is_some_and(|bp| bp.1.condition.is_some())
 7958        {
 7959            "Edit Condition Breakpoint"
 7960        } else {
 7961            "Set Condition Breakpoint"
 7962        };
 7963
 7964        let hit_condition_breakpoint_msg = if breakpoint
 7965            .as_ref()
 7966            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7967        {
 7968            "Edit Hit Condition Breakpoint"
 7969        } else {
 7970            "Set Hit Condition Breakpoint"
 7971        };
 7972
 7973        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7974            "Unset Breakpoint"
 7975        } else {
 7976            "Set Breakpoint"
 7977        };
 7978
 7979        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7980
 7981        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7982            BreakpointState::Enabled => Some("Disable"),
 7983            BreakpointState::Disabled => Some("Enable"),
 7984        });
 7985
 7986        let (anchor, breakpoint) =
 7987            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7988
 7989        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7990            menu.on_blur_subscription(Subscription::new(|| {}))
 7991                .context(focus_handle)
 7992                .when(run_to_cursor, |this| {
 7993                    let weak_editor = weak_editor.clone();
 7994                    this.entry("Run to cursor", None, move |window, cx| {
 7995                        weak_editor
 7996                            .update(cx, |editor, cx| {
 7997                                editor.change_selections(
 7998                                    SelectionEffects::no_scroll(),
 7999                                    window,
 8000                                    cx,
 8001                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8002                                );
 8003                            })
 8004                            .ok();
 8005
 8006                        window.dispatch_action(Box::new(RunToCursor), cx);
 8007                    })
 8008                    .separator()
 8009                })
 8010                .when_some(toggle_state_msg, |this, msg| {
 8011                    this.entry(msg, None, {
 8012                        let weak_editor = weak_editor.clone();
 8013                        let breakpoint = breakpoint.clone();
 8014                        move |_window, cx| {
 8015                            weak_editor
 8016                                .update(cx, |this, cx| {
 8017                                    this.edit_breakpoint_at_anchor(
 8018                                        anchor,
 8019                                        breakpoint.as_ref().clone(),
 8020                                        BreakpointEditAction::InvertState,
 8021                                        cx,
 8022                                    );
 8023                                })
 8024                                .log_err();
 8025                        }
 8026                    })
 8027                })
 8028                .entry(set_breakpoint_msg, None, {
 8029                    let weak_editor = weak_editor.clone();
 8030                    let breakpoint = breakpoint.clone();
 8031                    move |_window, cx| {
 8032                        weak_editor
 8033                            .update(cx, |this, cx| {
 8034                                this.edit_breakpoint_at_anchor(
 8035                                    anchor,
 8036                                    breakpoint.as_ref().clone(),
 8037                                    BreakpointEditAction::Toggle,
 8038                                    cx,
 8039                                );
 8040                            })
 8041                            .log_err();
 8042                    }
 8043                })
 8044                .entry(log_breakpoint_msg, None, {
 8045                    let breakpoint = breakpoint.clone();
 8046                    let weak_editor = weak_editor.clone();
 8047                    move |window, cx| {
 8048                        weak_editor
 8049                            .update(cx, |this, cx| {
 8050                                this.add_edit_breakpoint_block(
 8051                                    anchor,
 8052                                    breakpoint.as_ref(),
 8053                                    BreakpointPromptEditAction::Log,
 8054                                    window,
 8055                                    cx,
 8056                                );
 8057                            })
 8058                            .log_err();
 8059                    }
 8060                })
 8061                .entry(condition_breakpoint_msg, None, {
 8062                    let breakpoint = breakpoint.clone();
 8063                    let weak_editor = weak_editor.clone();
 8064                    move |window, cx| {
 8065                        weak_editor
 8066                            .update(cx, |this, cx| {
 8067                                this.add_edit_breakpoint_block(
 8068                                    anchor,
 8069                                    breakpoint.as_ref(),
 8070                                    BreakpointPromptEditAction::Condition,
 8071                                    window,
 8072                                    cx,
 8073                                );
 8074                            })
 8075                            .log_err();
 8076                    }
 8077                })
 8078                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8079                    weak_editor
 8080                        .update(cx, |this, cx| {
 8081                            this.add_edit_breakpoint_block(
 8082                                anchor,
 8083                                breakpoint.as_ref(),
 8084                                BreakpointPromptEditAction::HitCondition,
 8085                                window,
 8086                                cx,
 8087                            );
 8088                        })
 8089                        .log_err();
 8090                })
 8091        })
 8092    }
 8093
 8094    fn render_breakpoint(
 8095        &self,
 8096        position: Anchor,
 8097        row: DisplayRow,
 8098        breakpoint: &Breakpoint,
 8099        state: Option<BreakpointSessionState>,
 8100        cx: &mut Context<Self>,
 8101    ) -> IconButton {
 8102        let is_rejected = state.is_some_and(|s| !s.verified);
 8103        // Is it a breakpoint that shows up when hovering over gutter?
 8104        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8105            (false, false),
 8106            |PhantomBreakpointIndicator {
 8107                 is_active,
 8108                 display_row,
 8109                 collides_with_existing_breakpoint,
 8110             }| {
 8111                (
 8112                    is_active && display_row == row,
 8113                    collides_with_existing_breakpoint,
 8114                )
 8115            },
 8116        );
 8117
 8118        let (color, icon) = {
 8119            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8120                (false, false) => ui::IconName::DebugBreakpoint,
 8121                (true, false) => ui::IconName::DebugLogBreakpoint,
 8122                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8123                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8124            };
 8125
 8126            let color = if is_phantom {
 8127                Color::Hint
 8128            } else if is_rejected {
 8129                Color::Disabled
 8130            } else {
 8131                Color::Debugger
 8132            };
 8133
 8134            (color, icon)
 8135        };
 8136
 8137        let breakpoint = Arc::from(breakpoint.clone());
 8138
 8139        let alt_as_text = gpui::Keystroke {
 8140            modifiers: Modifiers::secondary_key(),
 8141            ..Default::default()
 8142        };
 8143        let primary_action_text = if breakpoint.is_disabled() {
 8144            "Enable breakpoint"
 8145        } else if is_phantom && !collides_with_existing {
 8146            "Set breakpoint"
 8147        } else {
 8148            "Unset breakpoint"
 8149        };
 8150        let focus_handle = self.focus_handle.clone();
 8151
 8152        let meta = if is_rejected {
 8153            SharedString::from("No executable code is associated with this line.")
 8154        } else if collides_with_existing && !breakpoint.is_disabled() {
 8155            SharedString::from(format!(
 8156                "{alt_as_text}-click to disable,\nright-click for more options."
 8157            ))
 8158        } else {
 8159            SharedString::from("Right-click for more options.")
 8160        };
 8161        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8162            .icon_size(IconSize::XSmall)
 8163            .size(ui::ButtonSize::None)
 8164            .when(is_rejected, |this| {
 8165                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8166            })
 8167            .icon_color(color)
 8168            .style(ButtonStyle::Transparent)
 8169            .on_click(cx.listener({
 8170                let breakpoint = breakpoint.clone();
 8171
 8172                move |editor, event: &ClickEvent, window, cx| {
 8173                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8174                        BreakpointEditAction::InvertState
 8175                    } else {
 8176                        BreakpointEditAction::Toggle
 8177                    };
 8178
 8179                    window.focus(&editor.focus_handle(cx));
 8180                    editor.edit_breakpoint_at_anchor(
 8181                        position,
 8182                        breakpoint.as_ref().clone(),
 8183                        edit_action,
 8184                        cx,
 8185                    );
 8186                }
 8187            }))
 8188            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8189                editor.set_breakpoint_context_menu(
 8190                    row,
 8191                    Some(position),
 8192                    event.position(),
 8193                    window,
 8194                    cx,
 8195                );
 8196            }))
 8197            .tooltip(move |window, cx| {
 8198                Tooltip::with_meta_in(
 8199                    primary_action_text,
 8200                    Some(&ToggleBreakpoint),
 8201                    meta.clone(),
 8202                    &focus_handle,
 8203                    window,
 8204                    cx,
 8205                )
 8206            })
 8207    }
 8208
 8209    fn build_tasks_context(
 8210        project: &Entity<Project>,
 8211        buffer: &Entity<Buffer>,
 8212        buffer_row: u32,
 8213        tasks: &Arc<RunnableTasks>,
 8214        cx: &mut Context<Self>,
 8215    ) -> Task<Option<task::TaskContext>> {
 8216        let position = Point::new(buffer_row, tasks.column);
 8217        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8218        let location = Location {
 8219            buffer: buffer.clone(),
 8220            range: range_start..range_start,
 8221        };
 8222        // Fill in the environmental variables from the tree-sitter captures
 8223        let mut captured_task_variables = TaskVariables::default();
 8224        for (capture_name, value) in tasks.extra_variables.clone() {
 8225            captured_task_variables.insert(
 8226                task::VariableName::Custom(capture_name.into()),
 8227                value.clone(),
 8228            );
 8229        }
 8230        project.update(cx, |project, cx| {
 8231            project.task_store().update(cx, |task_store, cx| {
 8232                task_store.task_context_for_location(captured_task_variables, location, cx)
 8233            })
 8234        })
 8235    }
 8236
 8237    pub fn spawn_nearest_task(
 8238        &mut self,
 8239        action: &SpawnNearestTask,
 8240        window: &mut Window,
 8241        cx: &mut Context<Self>,
 8242    ) {
 8243        let Some((workspace, _)) = self.workspace.clone() else {
 8244            return;
 8245        };
 8246        let Some(project) = self.project.clone() else {
 8247            return;
 8248        };
 8249
 8250        // Try to find a closest, enclosing node using tree-sitter that has a task
 8251        let Some((buffer, buffer_row, tasks)) = self
 8252            .find_enclosing_node_task(cx)
 8253            // Or find the task that's closest in row-distance.
 8254            .or_else(|| self.find_closest_task(cx))
 8255        else {
 8256            return;
 8257        };
 8258
 8259        let reveal_strategy = action.reveal;
 8260        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8261        cx.spawn_in(window, async move |_, cx| {
 8262            let context = task_context.await?;
 8263            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8264
 8265            let resolved = &mut resolved_task.resolved;
 8266            resolved.reveal = reveal_strategy;
 8267
 8268            workspace
 8269                .update_in(cx, |workspace, window, cx| {
 8270                    workspace.schedule_resolved_task(
 8271                        task_source_kind,
 8272                        resolved_task,
 8273                        false,
 8274                        window,
 8275                        cx,
 8276                    );
 8277                })
 8278                .ok()
 8279        })
 8280        .detach();
 8281    }
 8282
 8283    fn find_closest_task(
 8284        &mut self,
 8285        cx: &mut Context<Self>,
 8286    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8287        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8288
 8289        let ((buffer_id, row), tasks) = self
 8290            .tasks
 8291            .iter()
 8292            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8293
 8294        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8295        let tasks = Arc::new(tasks.to_owned());
 8296        Some((buffer, *row, tasks))
 8297    }
 8298
 8299    fn find_enclosing_node_task(
 8300        &mut self,
 8301        cx: &mut Context<Self>,
 8302    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8303        let snapshot = self.buffer.read(cx).snapshot(cx);
 8304        let offset = self.selections.newest::<usize>(cx).head();
 8305        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8306        let buffer_id = excerpt.buffer().remote_id();
 8307
 8308        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8309        let mut cursor = layer.node().walk();
 8310
 8311        while cursor.goto_first_child_for_byte(offset).is_some() {
 8312            if cursor.node().end_byte() == offset {
 8313                cursor.goto_next_sibling();
 8314            }
 8315        }
 8316
 8317        // Ascend to the smallest ancestor that contains the range and has a task.
 8318        loop {
 8319            let node = cursor.node();
 8320            let node_range = node.byte_range();
 8321            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8322
 8323            // Check if this node contains our offset
 8324            if node_range.start <= offset && node_range.end >= offset {
 8325                // If it contains offset, check for task
 8326                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8327                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8328                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8329                }
 8330            }
 8331
 8332            if !cursor.goto_parent() {
 8333                break;
 8334            }
 8335        }
 8336        None
 8337    }
 8338
 8339    fn render_run_indicator(
 8340        &self,
 8341        _style: &EditorStyle,
 8342        is_active: bool,
 8343        row: DisplayRow,
 8344        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8345        cx: &mut Context<Self>,
 8346    ) -> IconButton {
 8347        let color = Color::Muted;
 8348        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8349
 8350        IconButton::new(
 8351            ("run_indicator", row.0 as usize),
 8352            ui::IconName::PlayOutlined,
 8353        )
 8354        .shape(ui::IconButtonShape::Square)
 8355        .icon_size(IconSize::XSmall)
 8356        .icon_color(color)
 8357        .toggle_state(is_active)
 8358        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8359            let quick_launch = match e {
 8360                ClickEvent::Keyboard(_) => true,
 8361                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8362            };
 8363
 8364            window.focus(&editor.focus_handle(cx));
 8365            editor.toggle_code_actions(
 8366                &ToggleCodeActions {
 8367                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8368                    quick_launch,
 8369                },
 8370                window,
 8371                cx,
 8372            );
 8373        }))
 8374        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8375            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8376        }))
 8377    }
 8378
 8379    pub fn context_menu_visible(&self) -> bool {
 8380        !self.edit_prediction_preview_is_active()
 8381            && self
 8382                .context_menu
 8383                .borrow()
 8384                .as_ref()
 8385                .map_or(false, |menu| menu.visible())
 8386    }
 8387
 8388    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8389        self.context_menu
 8390            .borrow()
 8391            .as_ref()
 8392            .map(|menu| menu.origin())
 8393    }
 8394
 8395    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8396        self.context_menu_options = Some(options);
 8397    }
 8398
 8399    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8400    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8401
 8402    fn render_edit_prediction_popover(
 8403        &mut self,
 8404        text_bounds: &Bounds<Pixels>,
 8405        content_origin: gpui::Point<Pixels>,
 8406        right_margin: Pixels,
 8407        editor_snapshot: &EditorSnapshot,
 8408        visible_row_range: Range<DisplayRow>,
 8409        scroll_top: f32,
 8410        scroll_bottom: f32,
 8411        line_layouts: &[LineWithInvisibles],
 8412        line_height: Pixels,
 8413        scroll_pixel_position: gpui::Point<Pixels>,
 8414        newest_selection_head: Option<DisplayPoint>,
 8415        editor_width: Pixels,
 8416        style: &EditorStyle,
 8417        window: &mut Window,
 8418        cx: &mut App,
 8419    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8420        if self.mode().is_minimap() {
 8421            return None;
 8422        }
 8423        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8424
 8425        if self.edit_prediction_visible_in_cursor_popover(true) {
 8426            return None;
 8427        }
 8428
 8429        match &active_edit_prediction.completion {
 8430            EditPrediction::Move { target, .. } => {
 8431                let target_display_point = target.to_display_point(editor_snapshot);
 8432
 8433                if self.edit_prediction_requires_modifier() {
 8434                    if !self.edit_prediction_preview_is_active() {
 8435                        return None;
 8436                    }
 8437
 8438                    self.render_edit_prediction_modifier_jump_popover(
 8439                        text_bounds,
 8440                        content_origin,
 8441                        visible_row_range,
 8442                        line_layouts,
 8443                        line_height,
 8444                        scroll_pixel_position,
 8445                        newest_selection_head,
 8446                        target_display_point,
 8447                        window,
 8448                        cx,
 8449                    )
 8450                } else {
 8451                    self.render_edit_prediction_eager_jump_popover(
 8452                        text_bounds,
 8453                        content_origin,
 8454                        editor_snapshot,
 8455                        visible_row_range,
 8456                        scroll_top,
 8457                        scroll_bottom,
 8458                        line_height,
 8459                        scroll_pixel_position,
 8460                        target_display_point,
 8461                        editor_width,
 8462                        window,
 8463                        cx,
 8464                    )
 8465                }
 8466            }
 8467            EditPrediction::Edit {
 8468                display_mode: EditDisplayMode::Inline,
 8469                ..
 8470            } => None,
 8471            EditPrediction::Edit {
 8472                display_mode: EditDisplayMode::TabAccept,
 8473                edits,
 8474                ..
 8475            } => {
 8476                let range = &edits.first()?.0;
 8477                let target_display_point = range.end.to_display_point(editor_snapshot);
 8478
 8479                self.render_edit_prediction_end_of_line_popover(
 8480                    "Accept",
 8481                    editor_snapshot,
 8482                    visible_row_range,
 8483                    target_display_point,
 8484                    line_height,
 8485                    scroll_pixel_position,
 8486                    content_origin,
 8487                    editor_width,
 8488                    window,
 8489                    cx,
 8490                )
 8491            }
 8492            EditPrediction::Edit {
 8493                edits,
 8494                edit_preview,
 8495                display_mode: EditDisplayMode::DiffPopover,
 8496                snapshot,
 8497            } => self.render_edit_prediction_diff_popover(
 8498                text_bounds,
 8499                content_origin,
 8500                right_margin,
 8501                editor_snapshot,
 8502                visible_row_range,
 8503                line_layouts,
 8504                line_height,
 8505                scroll_pixel_position,
 8506                newest_selection_head,
 8507                editor_width,
 8508                style,
 8509                edits,
 8510                edit_preview,
 8511                snapshot,
 8512                window,
 8513                cx,
 8514            ),
 8515        }
 8516    }
 8517
 8518    fn render_edit_prediction_modifier_jump_popover(
 8519        &mut self,
 8520        text_bounds: &Bounds<Pixels>,
 8521        content_origin: gpui::Point<Pixels>,
 8522        visible_row_range: Range<DisplayRow>,
 8523        line_layouts: &[LineWithInvisibles],
 8524        line_height: Pixels,
 8525        scroll_pixel_position: gpui::Point<Pixels>,
 8526        newest_selection_head: Option<DisplayPoint>,
 8527        target_display_point: DisplayPoint,
 8528        window: &mut Window,
 8529        cx: &mut App,
 8530    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8531        let scrolled_content_origin =
 8532            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8533
 8534        const SCROLL_PADDING_Y: Pixels = px(12.);
 8535
 8536        if target_display_point.row() < visible_row_range.start {
 8537            return self.render_edit_prediction_scroll_popover(
 8538                |_| SCROLL_PADDING_Y,
 8539                IconName::ArrowUp,
 8540                visible_row_range,
 8541                line_layouts,
 8542                newest_selection_head,
 8543                scrolled_content_origin,
 8544                window,
 8545                cx,
 8546            );
 8547        } else if target_display_point.row() >= visible_row_range.end {
 8548            return self.render_edit_prediction_scroll_popover(
 8549                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8550                IconName::ArrowDown,
 8551                visible_row_range,
 8552                line_layouts,
 8553                newest_selection_head,
 8554                scrolled_content_origin,
 8555                window,
 8556                cx,
 8557            );
 8558        }
 8559
 8560        const POLE_WIDTH: Pixels = px(2.);
 8561
 8562        let line_layout =
 8563            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8564        let target_column = target_display_point.column() as usize;
 8565
 8566        let target_x = line_layout.x_for_index(target_column);
 8567        let target_y =
 8568            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8569
 8570        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8571
 8572        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8573        border_color.l += 0.001;
 8574
 8575        let mut element = v_flex()
 8576            .items_end()
 8577            .when(flag_on_right, |el| el.items_start())
 8578            .child(if flag_on_right {
 8579                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8580                    .rounded_bl(px(0.))
 8581                    .rounded_tl(px(0.))
 8582                    .border_l_2()
 8583                    .border_color(border_color)
 8584            } else {
 8585                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8586                    .rounded_br(px(0.))
 8587                    .rounded_tr(px(0.))
 8588                    .border_r_2()
 8589                    .border_color(border_color)
 8590            })
 8591            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8592            .into_any();
 8593
 8594        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8595
 8596        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8597            - point(
 8598                if flag_on_right {
 8599                    POLE_WIDTH
 8600                } else {
 8601                    size.width - POLE_WIDTH
 8602                },
 8603                size.height - line_height,
 8604            );
 8605
 8606        origin.x = origin.x.max(content_origin.x);
 8607
 8608        element.prepaint_at(origin, window, cx);
 8609
 8610        Some((element, origin))
 8611    }
 8612
 8613    fn render_edit_prediction_scroll_popover(
 8614        &mut self,
 8615        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8616        scroll_icon: IconName,
 8617        visible_row_range: Range<DisplayRow>,
 8618        line_layouts: &[LineWithInvisibles],
 8619        newest_selection_head: Option<DisplayPoint>,
 8620        scrolled_content_origin: gpui::Point<Pixels>,
 8621        window: &mut Window,
 8622        cx: &mut App,
 8623    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8624        let mut element = self
 8625            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8626            .into_any();
 8627
 8628        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8629
 8630        let cursor = newest_selection_head?;
 8631        let cursor_row_layout =
 8632            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8633        let cursor_column = cursor.column() as usize;
 8634
 8635        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8636
 8637        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8638
 8639        element.prepaint_at(origin, window, cx);
 8640        Some((element, origin))
 8641    }
 8642
 8643    fn render_edit_prediction_eager_jump_popover(
 8644        &mut self,
 8645        text_bounds: &Bounds<Pixels>,
 8646        content_origin: gpui::Point<Pixels>,
 8647        editor_snapshot: &EditorSnapshot,
 8648        visible_row_range: Range<DisplayRow>,
 8649        scroll_top: f32,
 8650        scroll_bottom: f32,
 8651        line_height: Pixels,
 8652        scroll_pixel_position: gpui::Point<Pixels>,
 8653        target_display_point: DisplayPoint,
 8654        editor_width: Pixels,
 8655        window: &mut Window,
 8656        cx: &mut App,
 8657    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8658        if target_display_point.row().as_f32() < scroll_top {
 8659            let mut element = self
 8660                .render_edit_prediction_line_popover(
 8661                    "Jump to Edit",
 8662                    Some(IconName::ArrowUp),
 8663                    window,
 8664                    cx,
 8665                )?
 8666                .into_any();
 8667
 8668            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8669            let offset = point(
 8670                (text_bounds.size.width - size.width) / 2.,
 8671                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8672            );
 8673
 8674            let origin = text_bounds.origin + offset;
 8675            element.prepaint_at(origin, window, cx);
 8676            Some((element, origin))
 8677        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8678            let mut element = self
 8679                .render_edit_prediction_line_popover(
 8680                    "Jump to Edit",
 8681                    Some(IconName::ArrowDown),
 8682                    window,
 8683                    cx,
 8684                )?
 8685                .into_any();
 8686
 8687            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8688            let offset = point(
 8689                (text_bounds.size.width - size.width) / 2.,
 8690                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8691            );
 8692
 8693            let origin = text_bounds.origin + offset;
 8694            element.prepaint_at(origin, window, cx);
 8695            Some((element, origin))
 8696        } else {
 8697            self.render_edit_prediction_end_of_line_popover(
 8698                "Jump to Edit",
 8699                editor_snapshot,
 8700                visible_row_range,
 8701                target_display_point,
 8702                line_height,
 8703                scroll_pixel_position,
 8704                content_origin,
 8705                editor_width,
 8706                window,
 8707                cx,
 8708            )
 8709        }
 8710    }
 8711
 8712    fn render_edit_prediction_end_of_line_popover(
 8713        self: &mut Editor,
 8714        label: &'static str,
 8715        editor_snapshot: &EditorSnapshot,
 8716        visible_row_range: Range<DisplayRow>,
 8717        target_display_point: DisplayPoint,
 8718        line_height: Pixels,
 8719        scroll_pixel_position: gpui::Point<Pixels>,
 8720        content_origin: gpui::Point<Pixels>,
 8721        editor_width: Pixels,
 8722        window: &mut Window,
 8723        cx: &mut App,
 8724    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8725        let target_line_end = DisplayPoint::new(
 8726            target_display_point.row(),
 8727            editor_snapshot.line_len(target_display_point.row()),
 8728        );
 8729
 8730        let mut element = self
 8731            .render_edit_prediction_line_popover(label, None, window, cx)?
 8732            .into_any();
 8733
 8734        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8735
 8736        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8737
 8738        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8739        let mut origin = start_point
 8740            + line_origin
 8741            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8742        origin.x = origin.x.max(content_origin.x);
 8743
 8744        let max_x = content_origin.x + editor_width - size.width;
 8745
 8746        if origin.x > max_x {
 8747            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8748
 8749            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8750                origin.y += offset;
 8751                IconName::ArrowUp
 8752            } else {
 8753                origin.y -= offset;
 8754                IconName::ArrowDown
 8755            };
 8756
 8757            element = self
 8758                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8759                .into_any();
 8760
 8761            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8762
 8763            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8764        }
 8765
 8766        element.prepaint_at(origin, window, cx);
 8767        Some((element, origin))
 8768    }
 8769
 8770    fn render_edit_prediction_diff_popover(
 8771        self: &Editor,
 8772        text_bounds: &Bounds<Pixels>,
 8773        content_origin: gpui::Point<Pixels>,
 8774        right_margin: Pixels,
 8775        editor_snapshot: &EditorSnapshot,
 8776        visible_row_range: Range<DisplayRow>,
 8777        line_layouts: &[LineWithInvisibles],
 8778        line_height: Pixels,
 8779        scroll_pixel_position: gpui::Point<Pixels>,
 8780        newest_selection_head: Option<DisplayPoint>,
 8781        editor_width: Pixels,
 8782        style: &EditorStyle,
 8783        edits: &Vec<(Range<Anchor>, String)>,
 8784        edit_preview: &Option<language::EditPreview>,
 8785        snapshot: &language::BufferSnapshot,
 8786        window: &mut Window,
 8787        cx: &mut App,
 8788    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8789        let edit_start = edits
 8790            .first()
 8791            .unwrap()
 8792            .0
 8793            .start
 8794            .to_display_point(editor_snapshot);
 8795        let edit_end = edits
 8796            .last()
 8797            .unwrap()
 8798            .0
 8799            .end
 8800            .to_display_point(editor_snapshot);
 8801
 8802        let is_visible = visible_row_range.contains(&edit_start.row())
 8803            || visible_row_range.contains(&edit_end.row());
 8804        if !is_visible {
 8805            return None;
 8806        }
 8807
 8808        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8809            crate::edit_prediction_edit_text(&snapshot, edits, edit_preview, false, cx)
 8810        } else {
 8811            // Fallback for providers without edit_preview
 8812            crate::edit_prediction_fallback_text(edits, cx)
 8813        };
 8814
 8815        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8816        let line_count = highlighted_edits.text.lines().count();
 8817
 8818        const BORDER_WIDTH: Pixels = px(1.);
 8819
 8820        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8821        let has_keybind = keybind.is_some();
 8822
 8823        let mut element = h_flex()
 8824            .items_start()
 8825            .child(
 8826                h_flex()
 8827                    .bg(cx.theme().colors().editor_background)
 8828                    .border(BORDER_WIDTH)
 8829                    .shadow_xs()
 8830                    .border_color(cx.theme().colors().border)
 8831                    .rounded_l_lg()
 8832                    .when(line_count > 1, |el| el.rounded_br_lg())
 8833                    .pr_1()
 8834                    .child(styled_text),
 8835            )
 8836            .child(
 8837                h_flex()
 8838                    .h(line_height + BORDER_WIDTH * 2.)
 8839                    .px_1p5()
 8840                    .gap_1()
 8841                    // Workaround: For some reason, there's a gap if we don't do this
 8842                    .ml(-BORDER_WIDTH)
 8843                    .shadow(vec![gpui::BoxShadow {
 8844                        color: gpui::black().opacity(0.05),
 8845                        offset: point(px(1.), px(1.)),
 8846                        blur_radius: px(2.),
 8847                        spread_radius: px(0.),
 8848                    }])
 8849                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8850                    .border(BORDER_WIDTH)
 8851                    .border_color(cx.theme().colors().border)
 8852                    .rounded_r_lg()
 8853                    .id("edit_prediction_diff_popover_keybind")
 8854                    .when(!has_keybind, |el| {
 8855                        let status_colors = cx.theme().status();
 8856
 8857                        el.bg(status_colors.error_background)
 8858                            .border_color(status_colors.error.opacity(0.6))
 8859                            .child(Icon::new(IconName::Info).color(Color::Error))
 8860                            .cursor_default()
 8861                            .hoverable_tooltip(move |_window, cx| {
 8862                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8863                            })
 8864                    })
 8865                    .children(keybind),
 8866            )
 8867            .into_any();
 8868
 8869        let longest_row =
 8870            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8871        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8872            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8873        } else {
 8874            layout_line(
 8875                longest_row,
 8876                editor_snapshot,
 8877                style,
 8878                editor_width,
 8879                |_| false,
 8880                window,
 8881                cx,
 8882            )
 8883            .width
 8884        };
 8885
 8886        let viewport_bounds =
 8887            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8888                right: -right_margin,
 8889                ..Default::default()
 8890            });
 8891
 8892        let x_after_longest =
 8893            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8894                - scroll_pixel_position.x;
 8895
 8896        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8897
 8898        // Fully visible if it can be displayed within the window (allow overlapping other
 8899        // panes). However, this is only allowed if the popover starts within text_bounds.
 8900        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8901            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8902
 8903        let mut origin = if can_position_to_the_right {
 8904            point(
 8905                x_after_longest,
 8906                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8907                    - scroll_pixel_position.y,
 8908            )
 8909        } else {
 8910            let cursor_row = newest_selection_head.map(|head| head.row());
 8911            let above_edit = edit_start
 8912                .row()
 8913                .0
 8914                .checked_sub(line_count as u32)
 8915                .map(DisplayRow);
 8916            let below_edit = Some(edit_end.row() + 1);
 8917            let above_cursor =
 8918                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8919            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8920
 8921            // Place the edit popover adjacent to the edit if there is a location
 8922            // available that is onscreen and does not obscure the cursor. Otherwise,
 8923            // place it adjacent to the cursor.
 8924            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8925                .into_iter()
 8926                .flatten()
 8927                .find(|&start_row| {
 8928                    let end_row = start_row + line_count as u32;
 8929                    visible_row_range.contains(&start_row)
 8930                        && visible_row_range.contains(&end_row)
 8931                        && cursor_row.map_or(true, |cursor_row| {
 8932                            !((start_row..end_row).contains(&cursor_row))
 8933                        })
 8934                })?;
 8935
 8936            content_origin
 8937                + point(
 8938                    -scroll_pixel_position.x,
 8939                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8940                )
 8941        };
 8942
 8943        origin.x -= BORDER_WIDTH;
 8944
 8945        window.defer_draw(element, origin, 1);
 8946
 8947        // Do not return an element, since it will already be drawn due to defer_draw.
 8948        None
 8949    }
 8950
 8951    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8952        px(30.)
 8953    }
 8954
 8955    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8956        if self.read_only(cx) {
 8957            cx.theme().players().read_only()
 8958        } else {
 8959            self.style.as_ref().unwrap().local_player
 8960        }
 8961    }
 8962
 8963    fn render_edit_prediction_accept_keybind(
 8964        &self,
 8965        window: &mut Window,
 8966        cx: &App,
 8967    ) -> Option<AnyElement> {
 8968        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8969        let accept_keystroke = accept_binding.keystroke()?;
 8970
 8971        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8972
 8973        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8974            Color::Accent
 8975        } else {
 8976            Color::Muted
 8977        };
 8978
 8979        h_flex()
 8980            .px_0p5()
 8981            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8982            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8983            .text_size(TextSize::XSmall.rems(cx))
 8984            .child(h_flex().children(ui::render_modifiers(
 8985                &accept_keystroke.modifiers,
 8986                PlatformStyle::platform(),
 8987                Some(modifiers_color),
 8988                Some(IconSize::XSmall.rems().into()),
 8989                true,
 8990            )))
 8991            .when(is_platform_style_mac, |parent| {
 8992                parent.child(accept_keystroke.key.clone())
 8993            })
 8994            .when(!is_platform_style_mac, |parent| {
 8995                parent.child(
 8996                    Key::new(
 8997                        util::capitalize(&accept_keystroke.key),
 8998                        Some(Color::Default),
 8999                    )
 9000                    .size(Some(IconSize::XSmall.rems().into())),
 9001                )
 9002            })
 9003            .into_any()
 9004            .into()
 9005    }
 9006
 9007    fn render_edit_prediction_line_popover(
 9008        &self,
 9009        label: impl Into<SharedString>,
 9010        icon: Option<IconName>,
 9011        window: &mut Window,
 9012        cx: &App,
 9013    ) -> Option<Stateful<Div>> {
 9014        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9015
 9016        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9017        let has_keybind = keybind.is_some();
 9018
 9019        let result = h_flex()
 9020            .id("ep-line-popover")
 9021            .py_0p5()
 9022            .pl_1()
 9023            .pr(padding_right)
 9024            .gap_1()
 9025            .rounded_md()
 9026            .border_1()
 9027            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9028            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9029            .shadow_xs()
 9030            .when(!has_keybind, |el| {
 9031                let status_colors = cx.theme().status();
 9032
 9033                el.bg(status_colors.error_background)
 9034                    .border_color(status_colors.error.opacity(0.6))
 9035                    .pl_2()
 9036                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9037                    .cursor_default()
 9038                    .hoverable_tooltip(move |_window, cx| {
 9039                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9040                    })
 9041            })
 9042            .children(keybind)
 9043            .child(
 9044                Label::new(label)
 9045                    .size(LabelSize::Small)
 9046                    .when(!has_keybind, |el| {
 9047                        el.color(cx.theme().status().error.into()).strikethrough()
 9048                    }),
 9049            )
 9050            .when(!has_keybind, |el| {
 9051                el.child(
 9052                    h_flex().ml_1().child(
 9053                        Icon::new(IconName::Info)
 9054                            .size(IconSize::Small)
 9055                            .color(cx.theme().status().error.into()),
 9056                    ),
 9057                )
 9058            })
 9059            .when_some(icon, |element, icon| {
 9060                element.child(
 9061                    div()
 9062                        .mt(px(1.5))
 9063                        .child(Icon::new(icon).size(IconSize::Small)),
 9064                )
 9065            });
 9066
 9067        Some(result)
 9068    }
 9069
 9070    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9071        let accent_color = cx.theme().colors().text_accent;
 9072        let editor_bg_color = cx.theme().colors().editor_background;
 9073        editor_bg_color.blend(accent_color.opacity(0.1))
 9074    }
 9075
 9076    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9077        let accent_color = cx.theme().colors().text_accent;
 9078        let editor_bg_color = cx.theme().colors().editor_background;
 9079        editor_bg_color.blend(accent_color.opacity(0.6))
 9080    }
 9081    fn get_prediction_provider_icon_name(
 9082        provider: &Option<RegisteredEditPredictionProvider>,
 9083    ) -> IconName {
 9084        match provider {
 9085            Some(provider) => match provider.provider.name() {
 9086                "copilot" => IconName::Copilot,
 9087                "supermaven" => IconName::Supermaven,
 9088                _ => IconName::ZedPredict,
 9089            },
 9090            None => IconName::ZedPredict,
 9091        }
 9092    }
 9093
 9094    fn render_edit_prediction_cursor_popover(
 9095        &self,
 9096        min_width: Pixels,
 9097        max_width: Pixels,
 9098        cursor_point: Point,
 9099        style: &EditorStyle,
 9100        accept_keystroke: Option<&gpui::Keystroke>,
 9101        _window: &Window,
 9102        cx: &mut Context<Editor>,
 9103    ) -> Option<AnyElement> {
 9104        let provider = self.edit_prediction_provider.as_ref()?;
 9105        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9106
 9107        if provider.provider.needs_terms_acceptance(cx) {
 9108            return Some(
 9109                h_flex()
 9110                    .min_w(min_width)
 9111                    .flex_1()
 9112                    .px_2()
 9113                    .py_1()
 9114                    .gap_3()
 9115                    .elevation_2(cx)
 9116                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 9117                    .id("accept-terms")
 9118                    .cursor_pointer()
 9119                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 9120                    .on_click(cx.listener(|this, _event, window, cx| {
 9121                        cx.stop_propagation();
 9122                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 9123                        window.dispatch_action(
 9124                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 9125                            cx,
 9126                        );
 9127                    }))
 9128                    .child(
 9129                        h_flex()
 9130                            .flex_1()
 9131                            .gap_2()
 9132                            .child(Icon::new(provider_icon))
 9133                            .child(Label::new("Accept Terms of Service"))
 9134                            .child(div().w_full())
 9135                            .child(
 9136                                Icon::new(IconName::ArrowUpRight)
 9137                                    .color(Color::Muted)
 9138                                    .size(IconSize::Small),
 9139                            )
 9140                            .into_any_element(),
 9141                    )
 9142                    .into_any(),
 9143            );
 9144        }
 9145
 9146        let is_refreshing = provider.provider.is_refreshing(cx);
 9147
 9148        fn pending_completion_container(icon: IconName) -> Div {
 9149            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9150        }
 9151
 9152        let completion = match &self.active_edit_prediction {
 9153            Some(prediction) => {
 9154                if !self.has_visible_completions_menu() {
 9155                    const RADIUS: Pixels = px(6.);
 9156                    const BORDER_WIDTH: Pixels = px(1.);
 9157
 9158                    return Some(
 9159                        h_flex()
 9160                            .elevation_2(cx)
 9161                            .border(BORDER_WIDTH)
 9162                            .border_color(cx.theme().colors().border)
 9163                            .when(accept_keystroke.is_none(), |el| {
 9164                                el.border_color(cx.theme().status().error)
 9165                            })
 9166                            .rounded(RADIUS)
 9167                            .rounded_tl(px(0.))
 9168                            .overflow_hidden()
 9169                            .child(div().px_1p5().child(match &prediction.completion {
 9170                                EditPrediction::Move { target, snapshot } => {
 9171                                    use text::ToPoint as _;
 9172                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 9173                                    {
 9174                                        Icon::new(IconName::ZedPredictDown)
 9175                                    } else {
 9176                                        Icon::new(IconName::ZedPredictUp)
 9177                                    }
 9178                                }
 9179                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9180                            }))
 9181                            .child(
 9182                                h_flex()
 9183                                    .gap_1()
 9184                                    .py_1()
 9185                                    .px_2()
 9186                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9187                                    .border_l_1()
 9188                                    .border_color(cx.theme().colors().border)
 9189                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9190                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9191                                        el.child(
 9192                                            Label::new("Hold")
 9193                                                .size(LabelSize::Small)
 9194                                                .when(accept_keystroke.is_none(), |el| {
 9195                                                    el.strikethrough()
 9196                                                })
 9197                                                .line_height_style(LineHeightStyle::UiLabel),
 9198                                        )
 9199                                    })
 9200                                    .id("edit_prediction_cursor_popover_keybind")
 9201                                    .when(accept_keystroke.is_none(), |el| {
 9202                                        let status_colors = cx.theme().status();
 9203
 9204                                        el.bg(status_colors.error_background)
 9205                                            .border_color(status_colors.error.opacity(0.6))
 9206                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9207                                            .cursor_default()
 9208                                            .hoverable_tooltip(move |_window, cx| {
 9209                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9210                                                    .into()
 9211                                            })
 9212                                    })
 9213                                    .when_some(
 9214                                        accept_keystroke.as_ref(),
 9215                                        |el, accept_keystroke| {
 9216                                            el.child(h_flex().children(ui::render_modifiers(
 9217                                                &accept_keystroke.modifiers,
 9218                                                PlatformStyle::platform(),
 9219                                                Some(Color::Default),
 9220                                                Some(IconSize::XSmall.rems().into()),
 9221                                                false,
 9222                                            )))
 9223                                        },
 9224                                    ),
 9225                            )
 9226                            .into_any(),
 9227                    );
 9228                }
 9229
 9230                self.render_edit_prediction_cursor_popover_preview(
 9231                    prediction,
 9232                    cursor_point,
 9233                    style,
 9234                    cx,
 9235                )?
 9236            }
 9237
 9238            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9239                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9240                    stale_completion,
 9241                    cursor_point,
 9242                    style,
 9243                    cx,
 9244                )?,
 9245
 9246                None => pending_completion_container(provider_icon)
 9247                    .child(Label::new("...").size(LabelSize::Small)),
 9248            },
 9249
 9250            None => pending_completion_container(provider_icon)
 9251                .child(Label::new("...").size(LabelSize::Small)),
 9252        };
 9253
 9254        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9255            completion
 9256                .with_animation(
 9257                    "loading-completion",
 9258                    Animation::new(Duration::from_secs(2))
 9259                        .repeat()
 9260                        .with_easing(pulsating_between(0.4, 0.8)),
 9261                    |label, delta| label.opacity(delta),
 9262                )
 9263                .into_any_element()
 9264        } else {
 9265            completion.into_any_element()
 9266        };
 9267
 9268        let has_completion = self.active_edit_prediction.is_some();
 9269
 9270        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9271        Some(
 9272            h_flex()
 9273                .min_w(min_width)
 9274                .max_w(max_width)
 9275                .flex_1()
 9276                .elevation_2(cx)
 9277                .border_color(cx.theme().colors().border)
 9278                .child(
 9279                    div()
 9280                        .flex_1()
 9281                        .py_1()
 9282                        .px_2()
 9283                        .overflow_hidden()
 9284                        .child(completion),
 9285                )
 9286                .when_some(accept_keystroke, |el, accept_keystroke| {
 9287                    if !accept_keystroke.modifiers.modified() {
 9288                        return el;
 9289                    }
 9290
 9291                    el.child(
 9292                        h_flex()
 9293                            .h_full()
 9294                            .border_l_1()
 9295                            .rounded_r_lg()
 9296                            .border_color(cx.theme().colors().border)
 9297                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9298                            .gap_1()
 9299                            .py_1()
 9300                            .px_2()
 9301                            .child(
 9302                                h_flex()
 9303                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9304                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9305                                    .child(h_flex().children(ui::render_modifiers(
 9306                                        &accept_keystroke.modifiers,
 9307                                        PlatformStyle::platform(),
 9308                                        Some(if !has_completion {
 9309                                            Color::Muted
 9310                                        } else {
 9311                                            Color::Default
 9312                                        }),
 9313                                        None,
 9314                                        false,
 9315                                    ))),
 9316                            )
 9317                            .child(Label::new("Preview").into_any_element())
 9318                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9319                    )
 9320                })
 9321                .into_any(),
 9322        )
 9323    }
 9324
 9325    fn render_edit_prediction_cursor_popover_preview(
 9326        &self,
 9327        completion: &EditPredictionState,
 9328        cursor_point: Point,
 9329        style: &EditorStyle,
 9330        cx: &mut Context<Editor>,
 9331    ) -> Option<Div> {
 9332        use text::ToPoint as _;
 9333
 9334        fn render_relative_row_jump(
 9335            prefix: impl Into<String>,
 9336            current_row: u32,
 9337            target_row: u32,
 9338        ) -> Div {
 9339            let (row_diff, arrow) = if target_row < current_row {
 9340                (current_row - target_row, IconName::ArrowUp)
 9341            } else {
 9342                (target_row - current_row, IconName::ArrowDown)
 9343            };
 9344
 9345            h_flex()
 9346                .child(
 9347                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9348                        .color(Color::Muted)
 9349                        .size(LabelSize::Small),
 9350                )
 9351                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9352        }
 9353
 9354        let supports_jump = self
 9355            .edit_prediction_provider
 9356            .as_ref()
 9357            .map(|provider| provider.provider.supports_jump_to_edit())
 9358            .unwrap_or(true);
 9359
 9360        match &completion.completion {
 9361            EditPrediction::Move {
 9362                target, snapshot, ..
 9363            } => {
 9364                if !supports_jump {
 9365                    return None;
 9366                }
 9367
 9368                Some(
 9369                    h_flex()
 9370                        .px_2()
 9371                        .gap_2()
 9372                        .flex_1()
 9373                        .child(
 9374                            if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9375                                Icon::new(IconName::ZedPredictDown)
 9376                            } else {
 9377                                Icon::new(IconName::ZedPredictUp)
 9378                            },
 9379                        )
 9380                        .child(Label::new("Jump to Edit")),
 9381                )
 9382            }
 9383
 9384            EditPrediction::Edit {
 9385                edits,
 9386                edit_preview,
 9387                snapshot,
 9388                display_mode: _,
 9389            } => {
 9390                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9391
 9392                let (highlighted_edits, has_more_lines) =
 9393                    if let Some(edit_preview) = edit_preview.as_ref() {
 9394                        crate::edit_prediction_edit_text(&snapshot, &edits, edit_preview, true, cx)
 9395                            .first_line_preview()
 9396                    } else {
 9397                        crate::edit_prediction_fallback_text(&edits, cx).first_line_preview()
 9398                    };
 9399
 9400                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9401                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9402
 9403                let preview = h_flex()
 9404                    .gap_1()
 9405                    .min_w_16()
 9406                    .child(styled_text)
 9407                    .when(has_more_lines, |parent| parent.child(""));
 9408
 9409                let left = if supports_jump && first_edit_row != cursor_point.row {
 9410                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9411                        .into_any_element()
 9412                } else {
 9413                    let icon_name =
 9414                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9415                    Icon::new(icon_name).into_any_element()
 9416                };
 9417
 9418                Some(
 9419                    h_flex()
 9420                        .h_full()
 9421                        .flex_1()
 9422                        .gap_2()
 9423                        .pr_1()
 9424                        .overflow_x_hidden()
 9425                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9426                        .child(left)
 9427                        .child(preview),
 9428                )
 9429            }
 9430        }
 9431    }
 9432
 9433    pub fn render_context_menu(
 9434        &self,
 9435        style: &EditorStyle,
 9436        max_height_in_lines: u32,
 9437        window: &mut Window,
 9438        cx: &mut Context<Editor>,
 9439    ) -> Option<AnyElement> {
 9440        let menu = self.context_menu.borrow();
 9441        let menu = menu.as_ref()?;
 9442        if !menu.visible() {
 9443            return None;
 9444        };
 9445        Some(menu.render(style, max_height_in_lines, window, cx))
 9446    }
 9447
 9448    fn render_context_menu_aside(
 9449        &mut self,
 9450        max_size: Size<Pixels>,
 9451        window: &mut Window,
 9452        cx: &mut Context<Editor>,
 9453    ) -> Option<AnyElement> {
 9454        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9455            if menu.visible() {
 9456                menu.render_aside(max_size, window, cx)
 9457            } else {
 9458                None
 9459            }
 9460        })
 9461    }
 9462
 9463    fn hide_context_menu(
 9464        &mut self,
 9465        window: &mut Window,
 9466        cx: &mut Context<Self>,
 9467    ) -> Option<CodeContextMenu> {
 9468        cx.notify();
 9469        self.completion_tasks.clear();
 9470        let context_menu = self.context_menu.borrow_mut().take();
 9471        self.stale_edit_prediction_in_menu.take();
 9472        self.update_visible_edit_prediction(window, cx);
 9473        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9474            if let Some(completion_provider) = &self.completion_provider {
 9475                completion_provider.selection_changed(None, window, cx);
 9476            }
 9477        }
 9478        context_menu
 9479    }
 9480
 9481    fn show_snippet_choices(
 9482        &mut self,
 9483        choices: &Vec<String>,
 9484        selection: Range<Anchor>,
 9485        cx: &mut Context<Self>,
 9486    ) {
 9487        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9488            (Some(a), Some(b)) if a == b => a,
 9489            _ => {
 9490                log::error!("expected anchor range to have matching buffer IDs");
 9491                return;
 9492            }
 9493        };
 9494        let multi_buffer = self.buffer().read(cx);
 9495        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9496            return;
 9497        };
 9498
 9499        let id = post_inc(&mut self.next_completion_id);
 9500        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9501        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9502            CompletionsMenu::new_snippet_choices(
 9503                id,
 9504                true,
 9505                choices,
 9506                selection,
 9507                buffer,
 9508                snippet_sort_order,
 9509            ),
 9510        ));
 9511    }
 9512
 9513    pub fn insert_snippet(
 9514        &mut self,
 9515        insertion_ranges: &[Range<usize>],
 9516        snippet: Snippet,
 9517        window: &mut Window,
 9518        cx: &mut Context<Self>,
 9519    ) -> Result<()> {
 9520        struct Tabstop<T> {
 9521            is_end_tabstop: bool,
 9522            ranges: Vec<Range<T>>,
 9523            choices: Option<Vec<String>>,
 9524        }
 9525
 9526        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9527            let snippet_text: Arc<str> = snippet.text.clone().into();
 9528            let edits = insertion_ranges
 9529                .iter()
 9530                .cloned()
 9531                .map(|range| (range, snippet_text.clone()));
 9532            let autoindent_mode = AutoindentMode::Block {
 9533                original_indent_columns: Vec::new(),
 9534            };
 9535            buffer.edit(edits, Some(autoindent_mode), cx);
 9536
 9537            let snapshot = &*buffer.read(cx);
 9538            let snippet = &snippet;
 9539            snippet
 9540                .tabstops
 9541                .iter()
 9542                .map(|tabstop| {
 9543                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9544                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9545                    });
 9546                    let mut tabstop_ranges = tabstop
 9547                        .ranges
 9548                        .iter()
 9549                        .flat_map(|tabstop_range| {
 9550                            let mut delta = 0_isize;
 9551                            insertion_ranges.iter().map(move |insertion_range| {
 9552                                let insertion_start = insertion_range.start as isize + delta;
 9553                                delta +=
 9554                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9555
 9556                                let start = ((insertion_start + tabstop_range.start) as usize)
 9557                                    .min(snapshot.len());
 9558                                let end = ((insertion_start + tabstop_range.end) as usize)
 9559                                    .min(snapshot.len());
 9560                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9561                            })
 9562                        })
 9563                        .collect::<Vec<_>>();
 9564                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9565
 9566                    Tabstop {
 9567                        is_end_tabstop,
 9568                        ranges: tabstop_ranges,
 9569                        choices: tabstop.choices.clone(),
 9570                    }
 9571                })
 9572                .collect::<Vec<_>>()
 9573        });
 9574        if let Some(tabstop) = tabstops.first() {
 9575            self.change_selections(Default::default(), window, cx, |s| {
 9576                // Reverse order so that the first range is the newest created selection.
 9577                // Completions will use it and autoscroll will prioritize it.
 9578                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9579            });
 9580
 9581            if let Some(choices) = &tabstop.choices {
 9582                if let Some(selection) = tabstop.ranges.first() {
 9583                    self.show_snippet_choices(choices, selection.clone(), cx)
 9584                }
 9585            }
 9586
 9587            // If we're already at the last tabstop and it's at the end of the snippet,
 9588            // we're done, we don't need to keep the state around.
 9589            if !tabstop.is_end_tabstop {
 9590                let choices = tabstops
 9591                    .iter()
 9592                    .map(|tabstop| tabstop.choices.clone())
 9593                    .collect();
 9594
 9595                let ranges = tabstops
 9596                    .into_iter()
 9597                    .map(|tabstop| tabstop.ranges)
 9598                    .collect::<Vec<_>>();
 9599
 9600                self.snippet_stack.push(SnippetState {
 9601                    active_index: 0,
 9602                    ranges,
 9603                    choices,
 9604                });
 9605            }
 9606
 9607            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9608            if self.autoclose_regions.is_empty() {
 9609                let snapshot = self.buffer.read(cx).snapshot(cx);
 9610                let mut all_selections = self.selections.all::<Point>(cx);
 9611                for selection in &mut all_selections {
 9612                    let selection_head = selection.head();
 9613                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9614                        continue;
 9615                    };
 9616
 9617                    let mut bracket_pair = None;
 9618                    let max_lookup_length = scope
 9619                        .brackets()
 9620                        .map(|(pair, _)| {
 9621                            pair.start
 9622                                .as_str()
 9623                                .chars()
 9624                                .count()
 9625                                .max(pair.end.as_str().chars().count())
 9626                        })
 9627                        .max();
 9628                    if let Some(max_lookup_length) = max_lookup_length {
 9629                        let next_text = snapshot
 9630                            .chars_at(selection_head)
 9631                            .take(max_lookup_length)
 9632                            .collect::<String>();
 9633                        let prev_text = snapshot
 9634                            .reversed_chars_at(selection_head)
 9635                            .take(max_lookup_length)
 9636                            .collect::<String>();
 9637
 9638                        for (pair, enabled) in scope.brackets() {
 9639                            if enabled
 9640                                && pair.close
 9641                                && prev_text.starts_with(pair.start.as_str())
 9642                                && next_text.starts_with(pair.end.as_str())
 9643                            {
 9644                                bracket_pair = Some(pair.clone());
 9645                                break;
 9646                            }
 9647                        }
 9648                    }
 9649
 9650                    if let Some(pair) = bracket_pair {
 9651                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9652                        let autoclose_enabled =
 9653                            self.use_autoclose && snapshot_settings.use_autoclose;
 9654                        if autoclose_enabled {
 9655                            let start = snapshot.anchor_after(selection_head);
 9656                            let end = snapshot.anchor_after(selection_head);
 9657                            self.autoclose_regions.push(AutocloseRegion {
 9658                                selection_id: selection.id,
 9659                                range: start..end,
 9660                                pair,
 9661                            });
 9662                        }
 9663                    }
 9664                }
 9665            }
 9666        }
 9667        Ok(())
 9668    }
 9669
 9670    pub fn move_to_next_snippet_tabstop(
 9671        &mut self,
 9672        window: &mut Window,
 9673        cx: &mut Context<Self>,
 9674    ) -> bool {
 9675        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9676    }
 9677
 9678    pub fn move_to_prev_snippet_tabstop(
 9679        &mut self,
 9680        window: &mut Window,
 9681        cx: &mut Context<Self>,
 9682    ) -> bool {
 9683        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9684    }
 9685
 9686    pub fn move_to_snippet_tabstop(
 9687        &mut self,
 9688        bias: Bias,
 9689        window: &mut Window,
 9690        cx: &mut Context<Self>,
 9691    ) -> bool {
 9692        if let Some(mut snippet) = self.snippet_stack.pop() {
 9693            match bias {
 9694                Bias::Left => {
 9695                    if snippet.active_index > 0 {
 9696                        snippet.active_index -= 1;
 9697                    } else {
 9698                        self.snippet_stack.push(snippet);
 9699                        return false;
 9700                    }
 9701                }
 9702                Bias::Right => {
 9703                    if snippet.active_index + 1 < snippet.ranges.len() {
 9704                        snippet.active_index += 1;
 9705                    } else {
 9706                        self.snippet_stack.push(snippet);
 9707                        return false;
 9708                    }
 9709                }
 9710            }
 9711            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9712                self.change_selections(Default::default(), window, cx, |s| {
 9713                    // Reverse order so that the first range is the newest created selection.
 9714                    // Completions will use it and autoscroll will prioritize it.
 9715                    s.select_ranges(current_ranges.iter().rev().cloned())
 9716                });
 9717
 9718                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9719                    if let Some(selection) = current_ranges.first() {
 9720                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9721                    }
 9722                }
 9723
 9724                // If snippet state is not at the last tabstop, push it back on the stack
 9725                if snippet.active_index + 1 < snippet.ranges.len() {
 9726                    self.snippet_stack.push(snippet);
 9727                }
 9728                return true;
 9729            }
 9730        }
 9731
 9732        false
 9733    }
 9734
 9735    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9736        self.transact(window, cx, |this, window, cx| {
 9737            this.select_all(&SelectAll, window, cx);
 9738            this.insert("", window, cx);
 9739        });
 9740    }
 9741
 9742    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9743        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9744        self.transact(window, cx, |this, window, cx| {
 9745            this.select_autoclose_pair(window, cx);
 9746            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9747            if !this.linked_edit_ranges.is_empty() {
 9748                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9749                let snapshot = this.buffer.read(cx).snapshot(cx);
 9750
 9751                for selection in selections.iter() {
 9752                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9753                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9754                    if selection_start.buffer_id != selection_end.buffer_id {
 9755                        continue;
 9756                    }
 9757                    if let Some(ranges) =
 9758                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9759                    {
 9760                        for (buffer, entries) in ranges {
 9761                            linked_ranges.entry(buffer).or_default().extend(entries);
 9762                        }
 9763                    }
 9764                }
 9765            }
 9766
 9767            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9768            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9769            for selection in &mut selections {
 9770                if selection.is_empty() {
 9771                    let old_head = selection.head();
 9772                    let mut new_head =
 9773                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9774                            .to_point(&display_map);
 9775                    if let Some((buffer, line_buffer_range)) = display_map
 9776                        .buffer_snapshot
 9777                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9778                    {
 9779                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9780                        let indent_len = match indent_size.kind {
 9781                            IndentKind::Space => {
 9782                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9783                            }
 9784                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9785                        };
 9786                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9787                            let indent_len = indent_len.get();
 9788                            new_head = cmp::min(
 9789                                new_head,
 9790                                MultiBufferPoint::new(
 9791                                    old_head.row,
 9792                                    ((old_head.column - 1) / indent_len) * indent_len,
 9793                                ),
 9794                            );
 9795                        }
 9796                    }
 9797
 9798                    selection.set_head(new_head, SelectionGoal::None);
 9799                }
 9800            }
 9801
 9802            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9803            this.insert("", window, cx);
 9804            let empty_str: Arc<str> = Arc::from("");
 9805            for (buffer, edits) in linked_ranges {
 9806                let snapshot = buffer.read(cx).snapshot();
 9807                use text::ToPoint as TP;
 9808
 9809                let edits = edits
 9810                    .into_iter()
 9811                    .map(|range| {
 9812                        let end_point = TP::to_point(&range.end, &snapshot);
 9813                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9814
 9815                        if end_point == start_point {
 9816                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9817                                .saturating_sub(1);
 9818                            start_point =
 9819                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9820                        };
 9821
 9822                        (start_point..end_point, empty_str.clone())
 9823                    })
 9824                    .sorted_by_key(|(range, _)| range.start)
 9825                    .collect::<Vec<_>>();
 9826                buffer.update(cx, |this, cx| {
 9827                    this.edit(edits, None, cx);
 9828                })
 9829            }
 9830            this.refresh_edit_prediction(true, false, window, cx);
 9831            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9832        });
 9833    }
 9834
 9835    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9836        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9837        self.transact(window, cx, |this, window, cx| {
 9838            this.change_selections(Default::default(), window, cx, |s| {
 9839                s.move_with(|map, selection| {
 9840                    if selection.is_empty() {
 9841                        let cursor = movement::right(map, selection.head());
 9842                        selection.end = cursor;
 9843                        selection.reversed = true;
 9844                        selection.goal = SelectionGoal::None;
 9845                    }
 9846                })
 9847            });
 9848            this.insert("", window, cx);
 9849            this.refresh_edit_prediction(true, false, window, cx);
 9850        });
 9851    }
 9852
 9853    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9854        if self.mode.is_single_line() {
 9855            cx.propagate();
 9856            return;
 9857        }
 9858
 9859        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9860        if self.move_to_prev_snippet_tabstop(window, cx) {
 9861            return;
 9862        }
 9863        self.outdent(&Outdent, window, cx);
 9864    }
 9865
 9866    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9867        if self.mode.is_single_line() {
 9868            cx.propagate();
 9869            return;
 9870        }
 9871
 9872        if self.move_to_next_snippet_tabstop(window, cx) {
 9873            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9874            return;
 9875        }
 9876        if self.read_only(cx) {
 9877            return;
 9878        }
 9879        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9880        let mut selections = self.selections.all_adjusted(cx);
 9881        let buffer = self.buffer.read(cx);
 9882        let snapshot = buffer.snapshot(cx);
 9883        let rows_iter = selections.iter().map(|s| s.head().row);
 9884        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9885
 9886        let has_some_cursor_in_whitespace = selections
 9887            .iter()
 9888            .filter(|selection| selection.is_empty())
 9889            .any(|selection| {
 9890                let cursor = selection.head();
 9891                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9892                cursor.column < current_indent.len
 9893            });
 9894
 9895        let mut edits = Vec::new();
 9896        let mut prev_edited_row = 0;
 9897        let mut row_delta = 0;
 9898        for selection in &mut selections {
 9899            if selection.start.row != prev_edited_row {
 9900                row_delta = 0;
 9901            }
 9902            prev_edited_row = selection.end.row;
 9903
 9904            // If the selection is non-empty, then increase the indentation of the selected lines.
 9905            if !selection.is_empty() {
 9906                row_delta =
 9907                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9908                continue;
 9909            }
 9910
 9911            let cursor = selection.head();
 9912            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9913            if let Some(suggested_indent) =
 9914                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9915            {
 9916                // Don't do anything if already at suggested indent
 9917                // and there is any other cursor which is not
 9918                if has_some_cursor_in_whitespace
 9919                    && cursor.column == current_indent.len
 9920                    && current_indent.len == suggested_indent.len
 9921                {
 9922                    continue;
 9923                }
 9924
 9925                // Adjust line and move cursor to suggested indent
 9926                // if cursor is not at suggested indent
 9927                if cursor.column < suggested_indent.len
 9928                    && cursor.column <= current_indent.len
 9929                    && current_indent.len <= suggested_indent.len
 9930                {
 9931                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9932                    selection.end = selection.start;
 9933                    if row_delta == 0 {
 9934                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9935                            cursor.row,
 9936                            current_indent,
 9937                            suggested_indent,
 9938                        ));
 9939                        row_delta = suggested_indent.len - current_indent.len;
 9940                    }
 9941                    continue;
 9942                }
 9943
 9944                // If current indent is more than suggested indent
 9945                // only move cursor to current indent and skip indent
 9946                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9947                    selection.start = Point::new(cursor.row, current_indent.len);
 9948                    selection.end = selection.start;
 9949                    continue;
 9950                }
 9951            }
 9952
 9953            // Otherwise, insert a hard or soft tab.
 9954            let settings = buffer.language_settings_at(cursor, cx);
 9955            let tab_size = if settings.hard_tabs {
 9956                IndentSize::tab()
 9957            } else {
 9958                let tab_size = settings.tab_size.get();
 9959                let indent_remainder = snapshot
 9960                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9961                    .flat_map(str::chars)
 9962                    .fold(row_delta % tab_size, |counter: u32, c| {
 9963                        if c == '\t' {
 9964                            0
 9965                        } else {
 9966                            (counter + 1) % tab_size
 9967                        }
 9968                    });
 9969
 9970                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9971                IndentSize::spaces(chars_to_next_tab_stop)
 9972            };
 9973            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9974            selection.end = selection.start;
 9975            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9976            row_delta += tab_size.len;
 9977        }
 9978
 9979        self.transact(window, cx, |this, window, cx| {
 9980            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9981            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9982            this.refresh_edit_prediction(true, false, window, cx);
 9983        });
 9984    }
 9985
 9986    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9987        if self.read_only(cx) {
 9988            return;
 9989        }
 9990        if self.mode.is_single_line() {
 9991            cx.propagate();
 9992            return;
 9993        }
 9994
 9995        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9996        let mut selections = self.selections.all::<Point>(cx);
 9997        let mut prev_edited_row = 0;
 9998        let mut row_delta = 0;
 9999        let mut edits = Vec::new();
10000        let buffer = self.buffer.read(cx);
10001        let snapshot = buffer.snapshot(cx);
10002        for selection in &mut selections {
10003            if selection.start.row != prev_edited_row {
10004                row_delta = 0;
10005            }
10006            prev_edited_row = selection.end.row;
10007
10008            row_delta =
10009                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10010        }
10011
10012        self.transact(window, cx, |this, window, cx| {
10013            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10014            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10015        });
10016    }
10017
10018    fn indent_selection(
10019        buffer: &MultiBuffer,
10020        snapshot: &MultiBufferSnapshot,
10021        selection: &mut Selection<Point>,
10022        edits: &mut Vec<(Range<Point>, String)>,
10023        delta_for_start_row: u32,
10024        cx: &App,
10025    ) -> u32 {
10026        let settings = buffer.language_settings_at(selection.start, cx);
10027        let tab_size = settings.tab_size.get();
10028        let indent_kind = if settings.hard_tabs {
10029            IndentKind::Tab
10030        } else {
10031            IndentKind::Space
10032        };
10033        let mut start_row = selection.start.row;
10034        let mut end_row = selection.end.row + 1;
10035
10036        // If a selection ends at the beginning of a line, don't indent
10037        // that last line.
10038        if selection.end.column == 0 && selection.end.row > selection.start.row {
10039            end_row -= 1;
10040        }
10041
10042        // Avoid re-indenting a row that has already been indented by a
10043        // previous selection, but still update this selection's column
10044        // to reflect that indentation.
10045        if delta_for_start_row > 0 {
10046            start_row += 1;
10047            selection.start.column += delta_for_start_row;
10048            if selection.end.row == selection.start.row {
10049                selection.end.column += delta_for_start_row;
10050            }
10051        }
10052
10053        let mut delta_for_end_row = 0;
10054        let has_multiple_rows = start_row + 1 != end_row;
10055        for row in start_row..end_row {
10056            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10057            let indent_delta = match (current_indent.kind, indent_kind) {
10058                (IndentKind::Space, IndentKind::Space) => {
10059                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10060                    IndentSize::spaces(columns_to_next_tab_stop)
10061                }
10062                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10063                (_, IndentKind::Tab) => IndentSize::tab(),
10064            };
10065
10066            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10067                0
10068            } else {
10069                selection.start.column
10070            };
10071            let row_start = Point::new(row, start);
10072            edits.push((
10073                row_start..row_start,
10074                indent_delta.chars().collect::<String>(),
10075            ));
10076
10077            // Update this selection's endpoints to reflect the indentation.
10078            if row == selection.start.row {
10079                selection.start.column += indent_delta.len;
10080            }
10081            if row == selection.end.row {
10082                selection.end.column += indent_delta.len;
10083                delta_for_end_row = indent_delta.len;
10084            }
10085        }
10086
10087        if selection.start.row == selection.end.row {
10088            delta_for_start_row + delta_for_end_row
10089        } else {
10090            delta_for_end_row
10091        }
10092    }
10093
10094    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10095        if self.read_only(cx) {
10096            return;
10097        }
10098        if self.mode.is_single_line() {
10099            cx.propagate();
10100            return;
10101        }
10102
10103        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10104        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10105        let selections = self.selections.all::<Point>(cx);
10106        let mut deletion_ranges = Vec::new();
10107        let mut last_outdent = None;
10108        {
10109            let buffer = self.buffer.read(cx);
10110            let snapshot = buffer.snapshot(cx);
10111            for selection in &selections {
10112                let settings = buffer.language_settings_at(selection.start, cx);
10113                let tab_size = settings.tab_size.get();
10114                let mut rows = selection.spanned_rows(false, &display_map);
10115
10116                // Avoid re-outdenting a row that has already been outdented by a
10117                // previous selection.
10118                if let Some(last_row) = last_outdent {
10119                    if last_row == rows.start {
10120                        rows.start = rows.start.next_row();
10121                    }
10122                }
10123                let has_multiple_rows = rows.len() > 1;
10124                for row in rows.iter_rows() {
10125                    let indent_size = snapshot.indent_size_for_line(row);
10126                    if indent_size.len > 0 {
10127                        let deletion_len = match indent_size.kind {
10128                            IndentKind::Space => {
10129                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10130                                if columns_to_prev_tab_stop == 0 {
10131                                    tab_size
10132                                } else {
10133                                    columns_to_prev_tab_stop
10134                                }
10135                            }
10136                            IndentKind::Tab => 1,
10137                        };
10138                        let start = if has_multiple_rows
10139                            || deletion_len > selection.start.column
10140                            || indent_size.len < selection.start.column
10141                        {
10142                            0
10143                        } else {
10144                            selection.start.column - deletion_len
10145                        };
10146                        deletion_ranges.push(
10147                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10148                        );
10149                        last_outdent = Some(row);
10150                    }
10151                }
10152            }
10153        }
10154
10155        self.transact(window, cx, |this, window, cx| {
10156            this.buffer.update(cx, |buffer, cx| {
10157                let empty_str: Arc<str> = Arc::default();
10158                buffer.edit(
10159                    deletion_ranges
10160                        .into_iter()
10161                        .map(|range| (range, empty_str.clone())),
10162                    None,
10163                    cx,
10164                );
10165            });
10166            let selections = this.selections.all::<usize>(cx);
10167            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10168        });
10169    }
10170
10171    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10172        if self.read_only(cx) {
10173            return;
10174        }
10175        if self.mode.is_single_line() {
10176            cx.propagate();
10177            return;
10178        }
10179
10180        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10181        let selections = self
10182            .selections
10183            .all::<usize>(cx)
10184            .into_iter()
10185            .map(|s| s.range());
10186
10187        self.transact(window, cx, |this, window, cx| {
10188            this.buffer.update(cx, |buffer, cx| {
10189                buffer.autoindent_ranges(selections, cx);
10190            });
10191            let selections = this.selections.all::<usize>(cx);
10192            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10193        });
10194    }
10195
10196    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10197        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10198        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10199        let selections = self.selections.all::<Point>(cx);
10200
10201        let mut new_cursors = Vec::new();
10202        let mut edit_ranges = Vec::new();
10203        let mut selections = selections.iter().peekable();
10204        while let Some(selection) = selections.next() {
10205            let mut rows = selection.spanned_rows(false, &display_map);
10206            let goal_display_column = selection.head().to_display_point(&display_map).column();
10207
10208            // Accumulate contiguous regions of rows that we want to delete.
10209            while let Some(next_selection) = selections.peek() {
10210                let next_rows = next_selection.spanned_rows(false, &display_map);
10211                if next_rows.start <= rows.end {
10212                    rows.end = next_rows.end;
10213                    selections.next().unwrap();
10214                } else {
10215                    break;
10216                }
10217            }
10218
10219            let buffer = &display_map.buffer_snapshot;
10220            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10221            let edit_end;
10222            let cursor_buffer_row;
10223            if buffer.max_point().row >= rows.end.0 {
10224                // If there's a line after the range, delete the \n from the end of the row range
10225                // and position the cursor on the next line.
10226                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10227                cursor_buffer_row = rows.end;
10228            } else {
10229                // If there isn't a line after the range, delete the \n from the line before the
10230                // start of the row range and position the cursor there.
10231                edit_start = edit_start.saturating_sub(1);
10232                edit_end = buffer.len();
10233                cursor_buffer_row = rows.start.previous_row();
10234            }
10235
10236            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10237            *cursor.column_mut() =
10238                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10239
10240            new_cursors.push((
10241                selection.id,
10242                buffer.anchor_after(cursor.to_point(&display_map)),
10243            ));
10244            edit_ranges.push(edit_start..edit_end);
10245        }
10246
10247        self.transact(window, cx, |this, window, cx| {
10248            let buffer = this.buffer.update(cx, |buffer, cx| {
10249                let empty_str: Arc<str> = Arc::default();
10250                buffer.edit(
10251                    edit_ranges
10252                        .into_iter()
10253                        .map(|range| (range, empty_str.clone())),
10254                    None,
10255                    cx,
10256                );
10257                buffer.snapshot(cx)
10258            });
10259            let new_selections = new_cursors
10260                .into_iter()
10261                .map(|(id, cursor)| {
10262                    let cursor = cursor.to_point(&buffer);
10263                    Selection {
10264                        id,
10265                        start: cursor,
10266                        end: cursor,
10267                        reversed: false,
10268                        goal: SelectionGoal::None,
10269                    }
10270                })
10271                .collect();
10272
10273            this.change_selections(Default::default(), window, cx, |s| {
10274                s.select(new_selections);
10275            });
10276        });
10277    }
10278
10279    pub fn join_lines_impl(
10280        &mut self,
10281        insert_whitespace: bool,
10282        window: &mut Window,
10283        cx: &mut Context<Self>,
10284    ) {
10285        if self.read_only(cx) {
10286            return;
10287        }
10288        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10289        for selection in self.selections.all::<Point>(cx) {
10290            let start = MultiBufferRow(selection.start.row);
10291            // Treat single line selections as if they include the next line. Otherwise this action
10292            // would do nothing for single line selections individual cursors.
10293            let end = if selection.start.row == selection.end.row {
10294                MultiBufferRow(selection.start.row + 1)
10295            } else {
10296                MultiBufferRow(selection.end.row)
10297            };
10298
10299            if let Some(last_row_range) = row_ranges.last_mut() {
10300                if start <= last_row_range.end {
10301                    last_row_range.end = end;
10302                    continue;
10303                }
10304            }
10305            row_ranges.push(start..end);
10306        }
10307
10308        let snapshot = self.buffer.read(cx).snapshot(cx);
10309        let mut cursor_positions = Vec::new();
10310        for row_range in &row_ranges {
10311            let anchor = snapshot.anchor_before(Point::new(
10312                row_range.end.previous_row().0,
10313                snapshot.line_len(row_range.end.previous_row()),
10314            ));
10315            cursor_positions.push(anchor..anchor);
10316        }
10317
10318        self.transact(window, cx, |this, window, cx| {
10319            for row_range in row_ranges.into_iter().rev() {
10320                for row in row_range.iter_rows().rev() {
10321                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10322                    let next_line_row = row.next_row();
10323                    let indent = snapshot.indent_size_for_line(next_line_row);
10324                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10325
10326                    let replace =
10327                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10328                            " "
10329                        } else {
10330                            ""
10331                        };
10332
10333                    this.buffer.update(cx, |buffer, cx| {
10334                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10335                    });
10336                }
10337            }
10338
10339            this.change_selections(Default::default(), window, cx, |s| {
10340                s.select_anchor_ranges(cursor_positions)
10341            });
10342        });
10343    }
10344
10345    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10346        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10347        self.join_lines_impl(true, window, cx);
10348    }
10349
10350    pub fn sort_lines_case_sensitive(
10351        &mut self,
10352        _: &SortLinesCaseSensitive,
10353        window: &mut Window,
10354        cx: &mut Context<Self>,
10355    ) {
10356        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10357    }
10358
10359    pub fn sort_lines_by_length(
10360        &mut self,
10361        _: &SortLinesByLength,
10362        window: &mut Window,
10363        cx: &mut Context<Self>,
10364    ) {
10365        self.manipulate_immutable_lines(window, cx, |lines| {
10366            lines.sort_by_key(|&line| line.chars().count())
10367        })
10368    }
10369
10370    pub fn sort_lines_case_insensitive(
10371        &mut self,
10372        _: &SortLinesCaseInsensitive,
10373        window: &mut Window,
10374        cx: &mut Context<Self>,
10375    ) {
10376        self.manipulate_immutable_lines(window, cx, |lines| {
10377            lines.sort_by_key(|line| line.to_lowercase())
10378        })
10379    }
10380
10381    pub fn unique_lines_case_insensitive(
10382        &mut self,
10383        _: &UniqueLinesCaseInsensitive,
10384        window: &mut Window,
10385        cx: &mut Context<Self>,
10386    ) {
10387        self.manipulate_immutable_lines(window, cx, |lines| {
10388            let mut seen = HashSet::default();
10389            lines.retain(|line| seen.insert(line.to_lowercase()));
10390        })
10391    }
10392
10393    pub fn unique_lines_case_sensitive(
10394        &mut self,
10395        _: &UniqueLinesCaseSensitive,
10396        window: &mut Window,
10397        cx: &mut Context<Self>,
10398    ) {
10399        self.manipulate_immutable_lines(window, cx, |lines| {
10400            let mut seen = HashSet::default();
10401            lines.retain(|line| seen.insert(*line));
10402        })
10403    }
10404
10405    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10406        let Some(project) = self.project.clone() else {
10407            return;
10408        };
10409        self.reload(project, window, cx)
10410            .detach_and_notify_err(window, cx);
10411    }
10412
10413    pub fn restore_file(
10414        &mut self,
10415        _: &::git::RestoreFile,
10416        window: &mut Window,
10417        cx: &mut Context<Self>,
10418    ) {
10419        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10420        let mut buffer_ids = HashSet::default();
10421        let snapshot = self.buffer().read(cx).snapshot(cx);
10422        for selection in self.selections.all::<usize>(cx) {
10423            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10424        }
10425
10426        let buffer = self.buffer().read(cx);
10427        let ranges = buffer_ids
10428            .into_iter()
10429            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10430            .collect::<Vec<_>>();
10431
10432        self.restore_hunks_in_ranges(ranges, window, cx);
10433    }
10434
10435    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10436        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10437        let selections = self
10438            .selections
10439            .all(cx)
10440            .into_iter()
10441            .map(|s| s.range())
10442            .collect();
10443        self.restore_hunks_in_ranges(selections, window, cx);
10444    }
10445
10446    pub fn restore_hunks_in_ranges(
10447        &mut self,
10448        ranges: Vec<Range<Point>>,
10449        window: &mut Window,
10450        cx: &mut Context<Editor>,
10451    ) {
10452        let mut revert_changes = HashMap::default();
10453        let chunk_by = self
10454            .snapshot(window, cx)
10455            .hunks_for_ranges(ranges)
10456            .into_iter()
10457            .chunk_by(|hunk| hunk.buffer_id);
10458        for (buffer_id, hunks) in &chunk_by {
10459            let hunks = hunks.collect::<Vec<_>>();
10460            for hunk in &hunks {
10461                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10462            }
10463            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10464        }
10465        drop(chunk_by);
10466        if !revert_changes.is_empty() {
10467            self.transact(window, cx, |editor, window, cx| {
10468                editor.restore(revert_changes, window, cx);
10469            });
10470        }
10471    }
10472
10473    pub fn open_active_item_in_terminal(
10474        &mut self,
10475        _: &OpenInTerminal,
10476        window: &mut Window,
10477        cx: &mut Context<Self>,
10478    ) {
10479        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10480            let project_path = buffer.read(cx).project_path(cx)?;
10481            let project = self.project.as_ref()?.read(cx);
10482            let entry = project.entry_for_path(&project_path, cx)?;
10483            let parent = match &entry.canonical_path {
10484                Some(canonical_path) => canonical_path.to_path_buf(),
10485                None => project.absolute_path(&project_path, cx)?,
10486            }
10487            .parent()?
10488            .to_path_buf();
10489            Some(parent)
10490        }) {
10491            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10492        }
10493    }
10494
10495    fn set_breakpoint_context_menu(
10496        &mut self,
10497        display_row: DisplayRow,
10498        position: Option<Anchor>,
10499        clicked_point: gpui::Point<Pixels>,
10500        window: &mut Window,
10501        cx: &mut Context<Self>,
10502    ) {
10503        let source = self
10504            .buffer
10505            .read(cx)
10506            .snapshot(cx)
10507            .anchor_before(Point::new(display_row.0, 0u32));
10508
10509        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10510
10511        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10512            self,
10513            source,
10514            clicked_point,
10515            context_menu,
10516            window,
10517            cx,
10518        );
10519    }
10520
10521    fn add_edit_breakpoint_block(
10522        &mut self,
10523        anchor: Anchor,
10524        breakpoint: &Breakpoint,
10525        edit_action: BreakpointPromptEditAction,
10526        window: &mut Window,
10527        cx: &mut Context<Self>,
10528    ) {
10529        let weak_editor = cx.weak_entity();
10530        let bp_prompt = cx.new(|cx| {
10531            BreakpointPromptEditor::new(
10532                weak_editor,
10533                anchor,
10534                breakpoint.clone(),
10535                edit_action,
10536                window,
10537                cx,
10538            )
10539        });
10540
10541        let height = bp_prompt.update(cx, |this, cx| {
10542            this.prompt
10543                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10544        });
10545        let cloned_prompt = bp_prompt.clone();
10546        let blocks = vec![BlockProperties {
10547            style: BlockStyle::Sticky,
10548            placement: BlockPlacement::Above(anchor),
10549            height: Some(height),
10550            render: Arc::new(move |cx| {
10551                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10552                cloned_prompt.clone().into_any_element()
10553            }),
10554            priority: 0,
10555        }];
10556
10557        let focus_handle = bp_prompt.focus_handle(cx);
10558        window.focus(&focus_handle);
10559
10560        let block_ids = self.insert_blocks(blocks, None, cx);
10561        bp_prompt.update(cx, |prompt, _| {
10562            prompt.add_block_ids(block_ids);
10563        });
10564    }
10565
10566    pub(crate) fn breakpoint_at_row(
10567        &self,
10568        row: u32,
10569        window: &mut Window,
10570        cx: &mut Context<Self>,
10571    ) -> Option<(Anchor, Breakpoint)> {
10572        let snapshot = self.snapshot(window, cx);
10573        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10574
10575        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10576    }
10577
10578    pub(crate) fn breakpoint_at_anchor(
10579        &self,
10580        breakpoint_position: Anchor,
10581        snapshot: &EditorSnapshot,
10582        cx: &mut Context<Self>,
10583    ) -> Option<(Anchor, Breakpoint)> {
10584        let project = self.project.clone()?;
10585
10586        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10587            snapshot
10588                .buffer_snapshot
10589                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10590        })?;
10591
10592        let enclosing_excerpt = breakpoint_position.excerpt_id;
10593        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10594        let buffer_snapshot = buffer.read(cx).snapshot();
10595
10596        let row = buffer_snapshot
10597            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10598            .row;
10599
10600        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10601        let anchor_end = snapshot
10602            .buffer_snapshot
10603            .anchor_after(Point::new(row, line_len));
10604
10605        let bp = self
10606            .breakpoint_store
10607            .as_ref()?
10608            .read_with(cx, |breakpoint_store, cx| {
10609                breakpoint_store
10610                    .breakpoints(
10611                        &buffer,
10612                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10613                        &buffer_snapshot,
10614                        cx,
10615                    )
10616                    .next()
10617                    .and_then(|(bp, _)| {
10618                        let breakpoint_row = buffer_snapshot
10619                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10620                            .row;
10621
10622                        if breakpoint_row == row {
10623                            snapshot
10624                                .buffer_snapshot
10625                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10626                                .map(|position| (position, bp.bp.clone()))
10627                        } else {
10628                            None
10629                        }
10630                    })
10631            });
10632        bp
10633    }
10634
10635    pub fn edit_log_breakpoint(
10636        &mut self,
10637        _: &EditLogBreakpoint,
10638        window: &mut Window,
10639        cx: &mut Context<Self>,
10640    ) {
10641        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10642            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10643                message: None,
10644                state: BreakpointState::Enabled,
10645                condition: None,
10646                hit_condition: None,
10647            });
10648
10649            self.add_edit_breakpoint_block(
10650                anchor,
10651                &breakpoint,
10652                BreakpointPromptEditAction::Log,
10653                window,
10654                cx,
10655            );
10656        }
10657    }
10658
10659    fn breakpoints_at_cursors(
10660        &self,
10661        window: &mut Window,
10662        cx: &mut Context<Self>,
10663    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10664        let snapshot = self.snapshot(window, cx);
10665        let cursors = self
10666            .selections
10667            .disjoint_anchors()
10668            .into_iter()
10669            .map(|selection| {
10670                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10671
10672                let breakpoint_position = self
10673                    .breakpoint_at_row(cursor_position.row, window, cx)
10674                    .map(|bp| bp.0)
10675                    .unwrap_or_else(|| {
10676                        snapshot
10677                            .display_snapshot
10678                            .buffer_snapshot
10679                            .anchor_after(Point::new(cursor_position.row, 0))
10680                    });
10681
10682                let breakpoint = self
10683                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10684                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10685
10686                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10687            })
10688            // 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.
10689            .collect::<HashMap<Anchor, _>>();
10690
10691        cursors.into_iter().collect()
10692    }
10693
10694    pub fn enable_breakpoint(
10695        &mut self,
10696        _: &crate::actions::EnableBreakpoint,
10697        window: &mut Window,
10698        cx: &mut Context<Self>,
10699    ) {
10700        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10701            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10702                continue;
10703            };
10704            self.edit_breakpoint_at_anchor(
10705                anchor,
10706                breakpoint,
10707                BreakpointEditAction::InvertState,
10708                cx,
10709            );
10710        }
10711    }
10712
10713    pub fn disable_breakpoint(
10714        &mut self,
10715        _: &crate::actions::DisableBreakpoint,
10716        window: &mut Window,
10717        cx: &mut Context<Self>,
10718    ) {
10719        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10720            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10721                continue;
10722            };
10723            self.edit_breakpoint_at_anchor(
10724                anchor,
10725                breakpoint,
10726                BreakpointEditAction::InvertState,
10727                cx,
10728            );
10729        }
10730    }
10731
10732    pub fn toggle_breakpoint(
10733        &mut self,
10734        _: &crate::actions::ToggleBreakpoint,
10735        window: &mut Window,
10736        cx: &mut Context<Self>,
10737    ) {
10738        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10739            if let Some(breakpoint) = breakpoint {
10740                self.edit_breakpoint_at_anchor(
10741                    anchor,
10742                    breakpoint,
10743                    BreakpointEditAction::Toggle,
10744                    cx,
10745                );
10746            } else {
10747                self.edit_breakpoint_at_anchor(
10748                    anchor,
10749                    Breakpoint::new_standard(),
10750                    BreakpointEditAction::Toggle,
10751                    cx,
10752                );
10753            }
10754        }
10755    }
10756
10757    pub fn edit_breakpoint_at_anchor(
10758        &mut self,
10759        breakpoint_position: Anchor,
10760        breakpoint: Breakpoint,
10761        edit_action: BreakpointEditAction,
10762        cx: &mut Context<Self>,
10763    ) {
10764        let Some(breakpoint_store) = &self.breakpoint_store else {
10765            return;
10766        };
10767
10768        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10769            if breakpoint_position == Anchor::min() {
10770                self.buffer()
10771                    .read(cx)
10772                    .excerpt_buffer_ids()
10773                    .into_iter()
10774                    .next()
10775            } else {
10776                None
10777            }
10778        }) else {
10779            return;
10780        };
10781
10782        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10783            return;
10784        };
10785
10786        breakpoint_store.update(cx, |breakpoint_store, cx| {
10787            breakpoint_store.toggle_breakpoint(
10788                buffer,
10789                BreakpointWithPosition {
10790                    position: breakpoint_position.text_anchor,
10791                    bp: breakpoint,
10792                },
10793                edit_action,
10794                cx,
10795            );
10796        });
10797
10798        cx.notify();
10799    }
10800
10801    #[cfg(any(test, feature = "test-support"))]
10802    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10803        self.breakpoint_store.clone()
10804    }
10805
10806    pub fn prepare_restore_change(
10807        &self,
10808        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10809        hunk: &MultiBufferDiffHunk,
10810        cx: &mut App,
10811    ) -> Option<()> {
10812        if hunk.is_created_file() {
10813            return None;
10814        }
10815        let buffer = self.buffer.read(cx);
10816        let diff = buffer.diff_for(hunk.buffer_id)?;
10817        let buffer = buffer.buffer(hunk.buffer_id)?;
10818        let buffer = buffer.read(cx);
10819        let original_text = diff
10820            .read(cx)
10821            .base_text()
10822            .as_rope()
10823            .slice(hunk.diff_base_byte_range.clone());
10824        let buffer_snapshot = buffer.snapshot();
10825        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10826        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10827            probe
10828                .0
10829                .start
10830                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10831                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10832        }) {
10833            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10834            Some(())
10835        } else {
10836            None
10837        }
10838    }
10839
10840    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10841        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10842    }
10843
10844    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10845        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10846    }
10847
10848    fn manipulate_lines<M>(
10849        &mut self,
10850        window: &mut Window,
10851        cx: &mut Context<Self>,
10852        mut manipulate: M,
10853    ) where
10854        M: FnMut(&str) -> LineManipulationResult,
10855    {
10856        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10857
10858        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10859        let buffer = self.buffer.read(cx).snapshot(cx);
10860
10861        let mut edits = Vec::new();
10862
10863        let selections = self.selections.all::<Point>(cx);
10864        let mut selections = selections.iter().peekable();
10865        let mut contiguous_row_selections = Vec::new();
10866        let mut new_selections = Vec::new();
10867        let mut added_lines = 0;
10868        let mut removed_lines = 0;
10869
10870        while let Some(selection) = selections.next() {
10871            let (start_row, end_row) = consume_contiguous_rows(
10872                &mut contiguous_row_selections,
10873                selection,
10874                &display_map,
10875                &mut selections,
10876            );
10877
10878            let start_point = Point::new(start_row.0, 0);
10879            let end_point = Point::new(
10880                end_row.previous_row().0,
10881                buffer.line_len(end_row.previous_row()),
10882            );
10883            let text = buffer
10884                .text_for_range(start_point..end_point)
10885                .collect::<String>();
10886
10887            let LineManipulationResult {
10888                new_text,
10889                line_count_before,
10890                line_count_after,
10891            } = manipulate(&text);
10892
10893            edits.push((start_point..end_point, new_text));
10894
10895            // Selections must change based on added and removed line count
10896            let start_row =
10897                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10898            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10899            new_selections.push(Selection {
10900                id: selection.id,
10901                start: start_row,
10902                end: end_row,
10903                goal: SelectionGoal::None,
10904                reversed: selection.reversed,
10905            });
10906
10907            if line_count_after > line_count_before {
10908                added_lines += line_count_after - line_count_before;
10909            } else if line_count_before > line_count_after {
10910                removed_lines += line_count_before - line_count_after;
10911            }
10912        }
10913
10914        self.transact(window, cx, |this, window, cx| {
10915            let buffer = this.buffer.update(cx, |buffer, cx| {
10916                buffer.edit(edits, None, cx);
10917                buffer.snapshot(cx)
10918            });
10919
10920            // Recalculate offsets on newly edited buffer
10921            let new_selections = new_selections
10922                .iter()
10923                .map(|s| {
10924                    let start_point = Point::new(s.start.0, 0);
10925                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10926                    Selection {
10927                        id: s.id,
10928                        start: buffer.point_to_offset(start_point),
10929                        end: buffer.point_to_offset(end_point),
10930                        goal: s.goal,
10931                        reversed: s.reversed,
10932                    }
10933                })
10934                .collect();
10935
10936            this.change_selections(Default::default(), window, cx, |s| {
10937                s.select(new_selections);
10938            });
10939
10940            this.request_autoscroll(Autoscroll::fit(), cx);
10941        });
10942    }
10943
10944    fn manipulate_immutable_lines<Fn>(
10945        &mut self,
10946        window: &mut Window,
10947        cx: &mut Context<Self>,
10948        mut callback: Fn,
10949    ) where
10950        Fn: FnMut(&mut Vec<&str>),
10951    {
10952        self.manipulate_lines(window, cx, |text| {
10953            let mut lines: Vec<&str> = text.split('\n').collect();
10954            let line_count_before = lines.len();
10955
10956            callback(&mut lines);
10957
10958            LineManipulationResult {
10959                new_text: lines.join("\n"),
10960                line_count_before,
10961                line_count_after: lines.len(),
10962            }
10963        });
10964    }
10965
10966    fn manipulate_mutable_lines<Fn>(
10967        &mut self,
10968        window: &mut Window,
10969        cx: &mut Context<Self>,
10970        mut callback: Fn,
10971    ) where
10972        Fn: FnMut(&mut Vec<Cow<'_, str>>),
10973    {
10974        self.manipulate_lines(window, cx, |text| {
10975            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
10976            let line_count_before = lines.len();
10977
10978            callback(&mut lines);
10979
10980            LineManipulationResult {
10981                new_text: lines.join("\n"),
10982                line_count_before,
10983                line_count_after: lines.len(),
10984            }
10985        });
10986    }
10987
10988    pub fn convert_indentation_to_spaces(
10989        &mut self,
10990        _: &ConvertIndentationToSpaces,
10991        window: &mut Window,
10992        cx: &mut Context<Self>,
10993    ) {
10994        let settings = self.buffer.read(cx).language_settings(cx);
10995        let tab_size = settings.tab_size.get() as usize;
10996
10997        self.manipulate_mutable_lines(window, cx, |lines| {
10998            // Allocates a reasonably sized scratch buffer once for the whole loop
10999            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11000            // Avoids recomputing spaces that could be inserted many times
11001            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11002                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11003                .collect();
11004
11005            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11006                let mut chars = line.as_ref().chars();
11007                let mut col = 0;
11008                let mut changed = false;
11009
11010                while let Some(ch) = chars.next() {
11011                    match ch {
11012                        ' ' => {
11013                            reindented_line.push(' ');
11014                            col += 1;
11015                        }
11016                        '\t' => {
11017                            // \t are converted to spaces depending on the current column
11018                            let spaces_len = tab_size - (col % tab_size);
11019                            reindented_line.extend(&space_cache[spaces_len - 1]);
11020                            col += spaces_len;
11021                            changed = true;
11022                        }
11023                        _ => {
11024                            // If we dont append before break, the character is consumed
11025                            reindented_line.push(ch);
11026                            break;
11027                        }
11028                    }
11029                }
11030
11031                if !changed {
11032                    reindented_line.clear();
11033                    continue;
11034                }
11035                // Append the rest of the line and replace old reference with new one
11036                reindented_line.extend(chars);
11037                *line = Cow::Owned(reindented_line.clone());
11038                reindented_line.clear();
11039            }
11040        });
11041    }
11042
11043    pub fn convert_indentation_to_tabs(
11044        &mut self,
11045        _: &ConvertIndentationToTabs,
11046        window: &mut Window,
11047        cx: &mut Context<Self>,
11048    ) {
11049        let settings = self.buffer.read(cx).language_settings(cx);
11050        let tab_size = settings.tab_size.get() as usize;
11051
11052        self.manipulate_mutable_lines(window, cx, |lines| {
11053            // Allocates a reasonably sized buffer once for the whole loop
11054            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11055            // Avoids recomputing spaces that could be inserted many times
11056            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11057                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11058                .collect();
11059
11060            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11061                let mut chars = line.chars();
11062                let mut spaces_count = 0;
11063                let mut first_non_indent_char = None;
11064                let mut changed = false;
11065
11066                while let Some(ch) = chars.next() {
11067                    match ch {
11068                        ' ' => {
11069                            // Keep track of spaces. Append \t when we reach tab_size
11070                            spaces_count += 1;
11071                            changed = true;
11072                            if spaces_count == tab_size {
11073                                reindented_line.push('\t');
11074                                spaces_count = 0;
11075                            }
11076                        }
11077                        '\t' => {
11078                            reindented_line.push('\t');
11079                            spaces_count = 0;
11080                        }
11081                        _ => {
11082                            // Dont append it yet, we might have remaining spaces
11083                            first_non_indent_char = Some(ch);
11084                            break;
11085                        }
11086                    }
11087                }
11088
11089                if !changed {
11090                    reindented_line.clear();
11091                    continue;
11092                }
11093                // Remaining spaces that didn't make a full tab stop
11094                if spaces_count > 0 {
11095                    reindented_line.extend(&space_cache[spaces_count - 1]);
11096                }
11097                // If we consume an extra character that was not indentation, add it back
11098                if let Some(extra_char) = first_non_indent_char {
11099                    reindented_line.push(extra_char);
11100                }
11101                // Append the rest of the line and replace old reference with new one
11102                reindented_line.extend(chars);
11103                *line = Cow::Owned(reindented_line.clone());
11104                reindented_line.clear();
11105            }
11106        });
11107    }
11108
11109    pub fn convert_to_upper_case(
11110        &mut self,
11111        _: &ConvertToUpperCase,
11112        window: &mut Window,
11113        cx: &mut Context<Self>,
11114    ) {
11115        self.manipulate_text(window, cx, |text| text.to_uppercase())
11116    }
11117
11118    pub fn convert_to_lower_case(
11119        &mut self,
11120        _: &ConvertToLowerCase,
11121        window: &mut Window,
11122        cx: &mut Context<Self>,
11123    ) {
11124        self.manipulate_text(window, cx, |text| text.to_lowercase())
11125    }
11126
11127    pub fn convert_to_title_case(
11128        &mut self,
11129        _: &ConvertToTitleCase,
11130        window: &mut Window,
11131        cx: &mut Context<Self>,
11132    ) {
11133        self.manipulate_text(window, cx, |text| {
11134            text.split('\n')
11135                .map(|line| line.to_case(Case::Title))
11136                .join("\n")
11137        })
11138    }
11139
11140    pub fn convert_to_snake_case(
11141        &mut self,
11142        _: &ConvertToSnakeCase,
11143        window: &mut Window,
11144        cx: &mut Context<Self>,
11145    ) {
11146        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11147    }
11148
11149    pub fn convert_to_kebab_case(
11150        &mut self,
11151        _: &ConvertToKebabCase,
11152        window: &mut Window,
11153        cx: &mut Context<Self>,
11154    ) {
11155        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11156    }
11157
11158    pub fn convert_to_upper_camel_case(
11159        &mut self,
11160        _: &ConvertToUpperCamelCase,
11161        window: &mut Window,
11162        cx: &mut Context<Self>,
11163    ) {
11164        self.manipulate_text(window, cx, |text| {
11165            text.split('\n')
11166                .map(|line| line.to_case(Case::UpperCamel))
11167                .join("\n")
11168        })
11169    }
11170
11171    pub fn convert_to_lower_camel_case(
11172        &mut self,
11173        _: &ConvertToLowerCamelCase,
11174        window: &mut Window,
11175        cx: &mut Context<Self>,
11176    ) {
11177        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11178    }
11179
11180    pub fn convert_to_opposite_case(
11181        &mut self,
11182        _: &ConvertToOppositeCase,
11183        window: &mut Window,
11184        cx: &mut Context<Self>,
11185    ) {
11186        self.manipulate_text(window, cx, |text| {
11187            text.chars()
11188                .fold(String::with_capacity(text.len()), |mut t, c| {
11189                    if c.is_uppercase() {
11190                        t.extend(c.to_lowercase());
11191                    } else {
11192                        t.extend(c.to_uppercase());
11193                    }
11194                    t
11195                })
11196        })
11197    }
11198
11199    pub fn convert_to_sentence_case(
11200        &mut self,
11201        _: &ConvertToSentenceCase,
11202        window: &mut Window,
11203        cx: &mut Context<Self>,
11204    ) {
11205        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11206    }
11207
11208    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11209        self.manipulate_text(window, cx, |text| {
11210            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11211            if has_upper_case_characters {
11212                text.to_lowercase()
11213            } else {
11214                text.to_uppercase()
11215            }
11216        })
11217    }
11218
11219    pub fn convert_to_rot13(
11220        &mut self,
11221        _: &ConvertToRot13,
11222        window: &mut Window,
11223        cx: &mut Context<Self>,
11224    ) {
11225        self.manipulate_text(window, cx, |text| {
11226            text.chars()
11227                .map(|c| match c {
11228                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11229                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11230                    _ => c,
11231                })
11232                .collect()
11233        })
11234    }
11235
11236    pub fn convert_to_rot47(
11237        &mut self,
11238        _: &ConvertToRot47,
11239        window: &mut Window,
11240        cx: &mut Context<Self>,
11241    ) {
11242        self.manipulate_text(window, cx, |text| {
11243            text.chars()
11244                .map(|c| {
11245                    let code_point = c as u32;
11246                    if code_point >= 33 && code_point <= 126 {
11247                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11248                    }
11249                    c
11250                })
11251                .collect()
11252        })
11253    }
11254
11255    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11256    where
11257        Fn: FnMut(&str) -> String,
11258    {
11259        let buffer = self.buffer.read(cx).snapshot(cx);
11260
11261        let mut new_selections = Vec::new();
11262        let mut edits = Vec::new();
11263        let mut selection_adjustment = 0i32;
11264
11265        for selection in self.selections.all::<usize>(cx) {
11266            let selection_is_empty = selection.is_empty();
11267
11268            let (start, end) = if selection_is_empty {
11269                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11270                (word_range.start, word_range.end)
11271            } else {
11272                (selection.start, selection.end)
11273            };
11274
11275            let text = buffer.text_for_range(start..end).collect::<String>();
11276            let old_length = text.len() as i32;
11277            let text = callback(&text);
11278
11279            new_selections.push(Selection {
11280                start: (start as i32 - selection_adjustment) as usize,
11281                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11282                goal: SelectionGoal::None,
11283                ..selection
11284            });
11285
11286            selection_adjustment += old_length - text.len() as i32;
11287
11288            edits.push((start..end, text));
11289        }
11290
11291        self.transact(window, cx, |this, window, cx| {
11292            this.buffer.update(cx, |buffer, cx| {
11293                buffer.edit(edits, None, cx);
11294            });
11295
11296            this.change_selections(Default::default(), window, cx, |s| {
11297                s.select(new_selections);
11298            });
11299
11300            this.request_autoscroll(Autoscroll::fit(), cx);
11301        });
11302    }
11303
11304    pub fn move_selection_on_drop(
11305        &mut self,
11306        selection: &Selection<Anchor>,
11307        target: DisplayPoint,
11308        is_cut: bool,
11309        window: &mut Window,
11310        cx: &mut Context<Self>,
11311    ) {
11312        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11313        let buffer = &display_map.buffer_snapshot;
11314        let mut edits = Vec::new();
11315        let insert_point = display_map
11316            .clip_point(target, Bias::Left)
11317            .to_point(&display_map);
11318        let text = buffer
11319            .text_for_range(selection.start..selection.end)
11320            .collect::<String>();
11321        if is_cut {
11322            edits.push(((selection.start..selection.end), String::new()));
11323        }
11324        let insert_anchor = buffer.anchor_before(insert_point);
11325        edits.push(((insert_anchor..insert_anchor), text));
11326        let last_edit_start = insert_anchor.bias_left(buffer);
11327        let last_edit_end = insert_anchor.bias_right(buffer);
11328        self.transact(window, cx, |this, window, cx| {
11329            this.buffer.update(cx, |buffer, cx| {
11330                buffer.edit(edits, None, cx);
11331            });
11332            this.change_selections(Default::default(), window, cx, |s| {
11333                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11334            });
11335        });
11336    }
11337
11338    pub fn clear_selection_drag_state(&mut self) {
11339        self.selection_drag_state = SelectionDragState::None;
11340    }
11341
11342    pub fn duplicate(
11343        &mut self,
11344        upwards: bool,
11345        whole_lines: bool,
11346        window: &mut Window,
11347        cx: &mut Context<Self>,
11348    ) {
11349        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11350
11351        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11352        let buffer = &display_map.buffer_snapshot;
11353        let selections = self.selections.all::<Point>(cx);
11354
11355        let mut edits = Vec::new();
11356        let mut selections_iter = selections.iter().peekable();
11357        while let Some(selection) = selections_iter.next() {
11358            let mut rows = selection.spanned_rows(false, &display_map);
11359            // duplicate line-wise
11360            if whole_lines || selection.start == selection.end {
11361                // Avoid duplicating the same lines twice.
11362                while let Some(next_selection) = selections_iter.peek() {
11363                    let next_rows = next_selection.spanned_rows(false, &display_map);
11364                    if next_rows.start < rows.end {
11365                        rows.end = next_rows.end;
11366                        selections_iter.next().unwrap();
11367                    } else {
11368                        break;
11369                    }
11370                }
11371
11372                // Copy the text from the selected row region and splice it either at the start
11373                // or end of the region.
11374                let start = Point::new(rows.start.0, 0);
11375                let end = Point::new(
11376                    rows.end.previous_row().0,
11377                    buffer.line_len(rows.end.previous_row()),
11378                );
11379                let text = buffer
11380                    .text_for_range(start..end)
11381                    .chain(Some("\n"))
11382                    .collect::<String>();
11383                let insert_location = if upwards {
11384                    Point::new(rows.end.0, 0)
11385                } else {
11386                    start
11387                };
11388                edits.push((insert_location..insert_location, text));
11389            } else {
11390                // duplicate character-wise
11391                let start = selection.start;
11392                let end = selection.end;
11393                let text = buffer.text_for_range(start..end).collect::<String>();
11394                edits.push((selection.end..selection.end, text));
11395            }
11396        }
11397
11398        self.transact(window, cx, |this, _, cx| {
11399            this.buffer.update(cx, |buffer, cx| {
11400                buffer.edit(edits, None, cx);
11401            });
11402
11403            this.request_autoscroll(Autoscroll::fit(), cx);
11404        });
11405    }
11406
11407    pub fn duplicate_line_up(
11408        &mut self,
11409        _: &DuplicateLineUp,
11410        window: &mut Window,
11411        cx: &mut Context<Self>,
11412    ) {
11413        self.duplicate(true, true, window, cx);
11414    }
11415
11416    pub fn duplicate_line_down(
11417        &mut self,
11418        _: &DuplicateLineDown,
11419        window: &mut Window,
11420        cx: &mut Context<Self>,
11421    ) {
11422        self.duplicate(false, true, window, cx);
11423    }
11424
11425    pub fn duplicate_selection(
11426        &mut self,
11427        _: &DuplicateSelection,
11428        window: &mut Window,
11429        cx: &mut Context<Self>,
11430    ) {
11431        self.duplicate(false, false, window, cx);
11432    }
11433
11434    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11435        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11436        if self.mode.is_single_line() {
11437            cx.propagate();
11438            return;
11439        }
11440
11441        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11442        let buffer = self.buffer.read(cx).snapshot(cx);
11443
11444        let mut edits = Vec::new();
11445        let mut unfold_ranges = Vec::new();
11446        let mut refold_creases = Vec::new();
11447
11448        let selections = self.selections.all::<Point>(cx);
11449        let mut selections = selections.iter().peekable();
11450        let mut contiguous_row_selections = Vec::new();
11451        let mut new_selections = Vec::new();
11452
11453        while let Some(selection) = selections.next() {
11454            // Find all the selections that span a contiguous row range
11455            let (start_row, end_row) = consume_contiguous_rows(
11456                &mut contiguous_row_selections,
11457                selection,
11458                &display_map,
11459                &mut selections,
11460            );
11461
11462            // Move the text spanned by the row range to be before the line preceding the row range
11463            if start_row.0 > 0 {
11464                let range_to_move = Point::new(
11465                    start_row.previous_row().0,
11466                    buffer.line_len(start_row.previous_row()),
11467                )
11468                    ..Point::new(
11469                        end_row.previous_row().0,
11470                        buffer.line_len(end_row.previous_row()),
11471                    );
11472                let insertion_point = display_map
11473                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11474                    .0;
11475
11476                // Don't move lines across excerpts
11477                if buffer
11478                    .excerpt_containing(insertion_point..range_to_move.end)
11479                    .is_some()
11480                {
11481                    let text = buffer
11482                        .text_for_range(range_to_move.clone())
11483                        .flat_map(|s| s.chars())
11484                        .skip(1)
11485                        .chain(['\n'])
11486                        .collect::<String>();
11487
11488                    edits.push((
11489                        buffer.anchor_after(range_to_move.start)
11490                            ..buffer.anchor_before(range_to_move.end),
11491                        String::new(),
11492                    ));
11493                    let insertion_anchor = buffer.anchor_after(insertion_point);
11494                    edits.push((insertion_anchor..insertion_anchor, text));
11495
11496                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11497
11498                    // Move selections up
11499                    new_selections.extend(contiguous_row_selections.drain(..).map(
11500                        |mut selection| {
11501                            selection.start.row -= row_delta;
11502                            selection.end.row -= row_delta;
11503                            selection
11504                        },
11505                    ));
11506
11507                    // Move folds up
11508                    unfold_ranges.push(range_to_move.clone());
11509                    for fold in display_map.folds_in_range(
11510                        buffer.anchor_before(range_to_move.start)
11511                            ..buffer.anchor_after(range_to_move.end),
11512                    ) {
11513                        let mut start = fold.range.start.to_point(&buffer);
11514                        let mut end = fold.range.end.to_point(&buffer);
11515                        start.row -= row_delta;
11516                        end.row -= row_delta;
11517                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11518                    }
11519                }
11520            }
11521
11522            // If we didn't move line(s), preserve the existing selections
11523            new_selections.append(&mut contiguous_row_selections);
11524        }
11525
11526        self.transact(window, cx, |this, window, cx| {
11527            this.unfold_ranges(&unfold_ranges, true, true, cx);
11528            this.buffer.update(cx, |buffer, cx| {
11529                for (range, text) in edits {
11530                    buffer.edit([(range, text)], None, cx);
11531                }
11532            });
11533            this.fold_creases(refold_creases, true, window, cx);
11534            this.change_selections(Default::default(), window, cx, |s| {
11535                s.select(new_selections);
11536            })
11537        });
11538    }
11539
11540    pub fn move_line_down(
11541        &mut self,
11542        _: &MoveLineDown,
11543        window: &mut Window,
11544        cx: &mut Context<Self>,
11545    ) {
11546        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11547        if self.mode.is_single_line() {
11548            cx.propagate();
11549            return;
11550        }
11551
11552        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11553        let buffer = self.buffer.read(cx).snapshot(cx);
11554
11555        let mut edits = Vec::new();
11556        let mut unfold_ranges = Vec::new();
11557        let mut refold_creases = Vec::new();
11558
11559        let selections = self.selections.all::<Point>(cx);
11560        let mut selections = selections.iter().peekable();
11561        let mut contiguous_row_selections = Vec::new();
11562        let mut new_selections = Vec::new();
11563
11564        while let Some(selection) = selections.next() {
11565            // Find all the selections that span a contiguous row range
11566            let (start_row, end_row) = consume_contiguous_rows(
11567                &mut contiguous_row_selections,
11568                selection,
11569                &display_map,
11570                &mut selections,
11571            );
11572
11573            // Move the text spanned by the row range to be after the last line of the row range
11574            if end_row.0 <= buffer.max_point().row {
11575                let range_to_move =
11576                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11577                let insertion_point = display_map
11578                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11579                    .0;
11580
11581                // Don't move lines across excerpt boundaries
11582                if buffer
11583                    .excerpt_containing(range_to_move.start..insertion_point)
11584                    .is_some()
11585                {
11586                    let mut text = String::from("\n");
11587                    text.extend(buffer.text_for_range(range_to_move.clone()));
11588                    text.pop(); // Drop trailing newline
11589                    edits.push((
11590                        buffer.anchor_after(range_to_move.start)
11591                            ..buffer.anchor_before(range_to_move.end),
11592                        String::new(),
11593                    ));
11594                    let insertion_anchor = buffer.anchor_after(insertion_point);
11595                    edits.push((insertion_anchor..insertion_anchor, text));
11596
11597                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11598
11599                    // Move selections down
11600                    new_selections.extend(contiguous_row_selections.drain(..).map(
11601                        |mut selection| {
11602                            selection.start.row += row_delta;
11603                            selection.end.row += row_delta;
11604                            selection
11605                        },
11606                    ));
11607
11608                    // Move folds down
11609                    unfold_ranges.push(range_to_move.clone());
11610                    for fold in display_map.folds_in_range(
11611                        buffer.anchor_before(range_to_move.start)
11612                            ..buffer.anchor_after(range_to_move.end),
11613                    ) {
11614                        let mut start = fold.range.start.to_point(&buffer);
11615                        let mut end = fold.range.end.to_point(&buffer);
11616                        start.row += row_delta;
11617                        end.row += row_delta;
11618                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11619                    }
11620                }
11621            }
11622
11623            // If we didn't move line(s), preserve the existing selections
11624            new_selections.append(&mut contiguous_row_selections);
11625        }
11626
11627        self.transact(window, cx, |this, window, cx| {
11628            this.unfold_ranges(&unfold_ranges, true, true, cx);
11629            this.buffer.update(cx, |buffer, cx| {
11630                for (range, text) in edits {
11631                    buffer.edit([(range, text)], None, cx);
11632                }
11633            });
11634            this.fold_creases(refold_creases, true, window, cx);
11635            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11636        });
11637    }
11638
11639    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11640        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11641        let text_layout_details = &self.text_layout_details(window);
11642        self.transact(window, cx, |this, window, cx| {
11643            let edits = this.change_selections(Default::default(), window, cx, |s| {
11644                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11645                s.move_with(|display_map, selection| {
11646                    if !selection.is_empty() {
11647                        return;
11648                    }
11649
11650                    let mut head = selection.head();
11651                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11652                    if head.column() == display_map.line_len(head.row()) {
11653                        transpose_offset = display_map
11654                            .buffer_snapshot
11655                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11656                    }
11657
11658                    if transpose_offset == 0 {
11659                        return;
11660                    }
11661
11662                    *head.column_mut() += 1;
11663                    head = display_map.clip_point(head, Bias::Right);
11664                    let goal = SelectionGoal::HorizontalPosition(
11665                        display_map
11666                            .x_for_display_point(head, text_layout_details)
11667                            .into(),
11668                    );
11669                    selection.collapse_to(head, goal);
11670
11671                    let transpose_start = display_map
11672                        .buffer_snapshot
11673                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11674                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11675                        let transpose_end = display_map
11676                            .buffer_snapshot
11677                            .clip_offset(transpose_offset + 1, Bias::Right);
11678                        if let Some(ch) =
11679                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11680                        {
11681                            edits.push((transpose_start..transpose_offset, String::new()));
11682                            edits.push((transpose_end..transpose_end, ch.to_string()));
11683                        }
11684                    }
11685                });
11686                edits
11687            });
11688            this.buffer
11689                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11690            let selections = this.selections.all::<usize>(cx);
11691            this.change_selections(Default::default(), window, cx, |s| {
11692                s.select(selections);
11693            });
11694        });
11695    }
11696
11697    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11698        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11699        if self.mode.is_single_line() {
11700            cx.propagate();
11701            return;
11702        }
11703
11704        self.rewrap_impl(RewrapOptions::default(), cx)
11705    }
11706
11707    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11708        let buffer = self.buffer.read(cx).snapshot(cx);
11709        let selections = self.selections.all::<Point>(cx);
11710
11711        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11712        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11713            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11714                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11715                .peekable();
11716
11717            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11718                row
11719            } else {
11720                return Vec::new();
11721            };
11722
11723            let language_settings = buffer.language_settings_at(selection.head(), cx);
11724            let language_scope = buffer.language_scope_at(selection.head());
11725
11726            let indent_and_prefix_for_row =
11727                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11728                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11729                    let (comment_prefix, rewrap_prefix) =
11730                        if let Some(language_scope) = &language_scope {
11731                            let indent_end = Point::new(row, indent.len);
11732                            let comment_prefix = language_scope
11733                                .line_comment_prefixes()
11734                                .iter()
11735                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11736                                .map(|prefix| prefix.to_string());
11737                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11738                            let line_text_after_indent = buffer
11739                                .text_for_range(indent_end..line_end)
11740                                .collect::<String>();
11741                            let rewrap_prefix = language_scope
11742                                .rewrap_prefixes()
11743                                .iter()
11744                                .find_map(|prefix_regex| {
11745                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11746                                        if mat.start() == 0 {
11747                                            Some(mat.as_str().to_string())
11748                                        } else {
11749                                            None
11750                                        }
11751                                    })
11752                                })
11753                                .flatten();
11754                            (comment_prefix, rewrap_prefix)
11755                        } else {
11756                            (None, None)
11757                        };
11758                    (indent, comment_prefix, rewrap_prefix)
11759                };
11760
11761            let mut ranges = Vec::new();
11762            let from_empty_selection = selection.is_empty();
11763
11764            let mut current_range_start = first_row;
11765            let mut prev_row = first_row;
11766            let (
11767                mut current_range_indent,
11768                mut current_range_comment_prefix,
11769                mut current_range_rewrap_prefix,
11770            ) = indent_and_prefix_for_row(first_row);
11771
11772            for row in non_blank_rows_iter.skip(1) {
11773                let has_paragraph_break = row > prev_row + 1;
11774
11775                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11776                    indent_and_prefix_for_row(row);
11777
11778                let has_indent_change = row_indent != current_range_indent;
11779                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11780
11781                let has_boundary_change = has_comment_change
11782                    || row_rewrap_prefix.is_some()
11783                    || (has_indent_change && current_range_comment_prefix.is_some());
11784
11785                if has_paragraph_break || has_boundary_change {
11786                    ranges.push((
11787                        language_settings.clone(),
11788                        Point::new(current_range_start, 0)
11789                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11790                        current_range_indent,
11791                        current_range_comment_prefix.clone(),
11792                        current_range_rewrap_prefix.clone(),
11793                        from_empty_selection,
11794                    ));
11795                    current_range_start = row;
11796                    current_range_indent = row_indent;
11797                    current_range_comment_prefix = row_comment_prefix;
11798                    current_range_rewrap_prefix = row_rewrap_prefix;
11799                }
11800                prev_row = row;
11801            }
11802
11803            ranges.push((
11804                language_settings.clone(),
11805                Point::new(current_range_start, 0)
11806                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11807                current_range_indent,
11808                current_range_comment_prefix,
11809                current_range_rewrap_prefix,
11810                from_empty_selection,
11811            ));
11812
11813            ranges
11814        });
11815
11816        let mut edits = Vec::new();
11817        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11818
11819        for (
11820            language_settings,
11821            wrap_range,
11822            indent_size,
11823            comment_prefix,
11824            rewrap_prefix,
11825            from_empty_selection,
11826        ) in wrap_ranges
11827        {
11828            let mut start_row = wrap_range.start.row;
11829            let mut end_row = wrap_range.end.row;
11830
11831            // Skip selections that overlap with a range that has already been rewrapped.
11832            let selection_range = start_row..end_row;
11833            if rewrapped_row_ranges
11834                .iter()
11835                .any(|range| range.overlaps(&selection_range))
11836            {
11837                continue;
11838            }
11839
11840            let tab_size = language_settings.tab_size;
11841
11842            let indent_prefix = indent_size.chars().collect::<String>();
11843            let mut line_prefix = indent_prefix.clone();
11844            let mut inside_comment = false;
11845            if let Some(prefix) = &comment_prefix {
11846                line_prefix.push_str(prefix);
11847                inside_comment = true;
11848            }
11849            if let Some(prefix) = &rewrap_prefix {
11850                line_prefix.push_str(prefix);
11851            }
11852
11853            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11854                RewrapBehavior::InComments => inside_comment,
11855                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11856                RewrapBehavior::Anywhere => true,
11857            };
11858
11859            let should_rewrap = options.override_language_settings
11860                || allow_rewrap_based_on_language
11861                || self.hard_wrap.is_some();
11862            if !should_rewrap {
11863                continue;
11864            }
11865
11866            if from_empty_selection {
11867                'expand_upwards: while start_row > 0 {
11868                    let prev_row = start_row - 1;
11869                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11870                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11871                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11872                    {
11873                        start_row = prev_row;
11874                    } else {
11875                        break 'expand_upwards;
11876                    }
11877                }
11878
11879                'expand_downwards: while end_row < buffer.max_point().row {
11880                    let next_row = end_row + 1;
11881                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11882                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11883                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11884                    {
11885                        end_row = next_row;
11886                    } else {
11887                        break 'expand_downwards;
11888                    }
11889                }
11890            }
11891
11892            let start = Point::new(start_row, 0);
11893            let start_offset = start.to_offset(&buffer);
11894            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11895            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11896            let Some(lines_without_prefixes) = selection_text
11897                .lines()
11898                .enumerate()
11899                .map(|(ix, line)| {
11900                    let line_trimmed = line.trim_start();
11901                    if rewrap_prefix.is_some() && ix > 0 {
11902                        Ok(line_trimmed)
11903                    } else {
11904                        line_trimmed
11905                            .strip_prefix(&line_prefix.trim_start())
11906                            .with_context(|| {
11907                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11908                            })
11909                    }
11910                })
11911                .collect::<Result<Vec<_>, _>>()
11912                .log_err()
11913            else {
11914                continue;
11915            };
11916
11917            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11918                buffer
11919                    .language_settings_at(Point::new(start_row, 0), cx)
11920                    .preferred_line_length as usize
11921            });
11922
11923            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11924                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11925            } else {
11926                line_prefix.clone()
11927            };
11928
11929            let wrapped_text = wrap_with_prefix(
11930                line_prefix,
11931                subsequent_lines_prefix,
11932                lines_without_prefixes.join("\n"),
11933                wrap_column,
11934                tab_size,
11935                options.preserve_existing_whitespace,
11936            );
11937
11938            // TODO: should always use char-based diff while still supporting cursor behavior that
11939            // matches vim.
11940            let mut diff_options = DiffOptions::default();
11941            if options.override_language_settings {
11942                diff_options.max_word_diff_len = 0;
11943                diff_options.max_word_diff_line_count = 0;
11944            } else {
11945                diff_options.max_word_diff_len = usize::MAX;
11946                diff_options.max_word_diff_line_count = usize::MAX;
11947            }
11948
11949            for (old_range, new_text) in
11950                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11951            {
11952                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11953                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11954                edits.push((edit_start..edit_end, new_text));
11955            }
11956
11957            rewrapped_row_ranges.push(start_row..=end_row);
11958        }
11959
11960        self.buffer
11961            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11962    }
11963
11964    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11965        let mut text = String::new();
11966        let buffer = self.buffer.read(cx).snapshot(cx);
11967        let mut selections = self.selections.all::<Point>(cx);
11968        let mut clipboard_selections = Vec::with_capacity(selections.len());
11969        {
11970            let max_point = buffer.max_point();
11971            let mut is_first = true;
11972            for selection in &mut selections {
11973                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11974                if is_entire_line {
11975                    selection.start = Point::new(selection.start.row, 0);
11976                    if !selection.is_empty() && selection.end.column == 0 {
11977                        selection.end = cmp::min(max_point, selection.end);
11978                    } else {
11979                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11980                    }
11981                    selection.goal = SelectionGoal::None;
11982                }
11983                if is_first {
11984                    is_first = false;
11985                } else {
11986                    text += "\n";
11987                }
11988                let mut len = 0;
11989                for chunk in buffer.text_for_range(selection.start..selection.end) {
11990                    text.push_str(chunk);
11991                    len += chunk.len();
11992                }
11993                clipboard_selections.push(ClipboardSelection {
11994                    len,
11995                    is_entire_line,
11996                    first_line_indent: buffer
11997                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11998                        .len,
11999                });
12000            }
12001        }
12002
12003        self.transact(window, cx, |this, window, cx| {
12004            this.change_selections(Default::default(), window, cx, |s| {
12005                s.select(selections);
12006            });
12007            this.insert("", window, cx);
12008        });
12009        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12010    }
12011
12012    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12013        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12014        let item = self.cut_common(window, cx);
12015        cx.write_to_clipboard(item);
12016    }
12017
12018    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12019        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12020        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12021            s.move_with(|snapshot, sel| {
12022                if sel.is_empty() {
12023                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
12024                }
12025            });
12026        });
12027        let item = self.cut_common(window, cx);
12028        cx.set_global(KillRing(item))
12029    }
12030
12031    pub fn kill_ring_yank(
12032        &mut self,
12033        _: &KillRingYank,
12034        window: &mut Window,
12035        cx: &mut Context<Self>,
12036    ) {
12037        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12038        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12039            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12040                (kill_ring.text().to_string(), kill_ring.metadata_json())
12041            } else {
12042                return;
12043            }
12044        } else {
12045            return;
12046        };
12047        self.do_paste(&text, metadata, false, window, cx);
12048    }
12049
12050    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12051        self.do_copy(true, cx);
12052    }
12053
12054    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12055        self.do_copy(false, cx);
12056    }
12057
12058    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12059        let selections = self.selections.all::<Point>(cx);
12060        let buffer = self.buffer.read(cx).read(cx);
12061        let mut text = String::new();
12062
12063        let mut clipboard_selections = Vec::with_capacity(selections.len());
12064        {
12065            let max_point = buffer.max_point();
12066            let mut is_first = true;
12067            for selection in &selections {
12068                let mut start = selection.start;
12069                let mut end = selection.end;
12070                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12071                if is_entire_line {
12072                    start = Point::new(start.row, 0);
12073                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12074                }
12075
12076                let mut trimmed_selections = Vec::new();
12077                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12078                    let row = MultiBufferRow(start.row);
12079                    let first_indent = buffer.indent_size_for_line(row);
12080                    if first_indent.len == 0 || start.column > first_indent.len {
12081                        trimmed_selections.push(start..end);
12082                    } else {
12083                        trimmed_selections.push(
12084                            Point::new(row.0, first_indent.len)
12085                                ..Point::new(row.0, buffer.line_len(row)),
12086                        );
12087                        for row in start.row + 1..=end.row {
12088                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12089                            if row == end.row {
12090                                line_len = end.column;
12091                            }
12092                            if line_len == 0 {
12093                                trimmed_selections
12094                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12095                                continue;
12096                            }
12097                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12098                            if row_indent_size.len >= first_indent.len {
12099                                trimmed_selections.push(
12100                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12101                                );
12102                            } else {
12103                                trimmed_selections.clear();
12104                                trimmed_selections.push(start..end);
12105                                break;
12106                            }
12107                        }
12108                    }
12109                } else {
12110                    trimmed_selections.push(start..end);
12111                }
12112
12113                for trimmed_range in trimmed_selections {
12114                    if is_first {
12115                        is_first = false;
12116                    } else {
12117                        text += "\n";
12118                    }
12119                    let mut len = 0;
12120                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12121                        text.push_str(chunk);
12122                        len += chunk.len();
12123                    }
12124                    clipboard_selections.push(ClipboardSelection {
12125                        len,
12126                        is_entire_line,
12127                        first_line_indent: buffer
12128                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12129                            .len,
12130                    });
12131                }
12132            }
12133        }
12134
12135        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12136            text,
12137            clipboard_selections,
12138        ));
12139    }
12140
12141    pub fn do_paste(
12142        &mut self,
12143        text: &String,
12144        clipboard_selections: Option<Vec<ClipboardSelection>>,
12145        handle_entire_lines: bool,
12146        window: &mut Window,
12147        cx: &mut Context<Self>,
12148    ) {
12149        if self.read_only(cx) {
12150            return;
12151        }
12152
12153        let clipboard_text = Cow::Borrowed(text);
12154
12155        self.transact(window, cx, |this, window, cx| {
12156            if let Some(mut clipboard_selections) = clipboard_selections {
12157                let old_selections = this.selections.all::<usize>(cx);
12158                let all_selections_were_entire_line =
12159                    clipboard_selections.iter().all(|s| s.is_entire_line);
12160                let first_selection_indent_column =
12161                    clipboard_selections.first().map(|s| s.first_line_indent);
12162                if clipboard_selections.len() != old_selections.len() {
12163                    clipboard_selections.drain(..);
12164                }
12165                let cursor_offset = this.selections.last::<usize>(cx).head();
12166                let mut auto_indent_on_paste = true;
12167
12168                this.buffer.update(cx, |buffer, cx| {
12169                    let snapshot = buffer.read(cx);
12170                    auto_indent_on_paste = snapshot
12171                        .language_settings_at(cursor_offset, cx)
12172                        .auto_indent_on_paste;
12173
12174                    let mut start_offset = 0;
12175                    let mut edits = Vec::new();
12176                    let mut original_indent_columns = Vec::new();
12177                    for (ix, selection) in old_selections.iter().enumerate() {
12178                        let to_insert;
12179                        let entire_line;
12180                        let original_indent_column;
12181                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12182                            let end_offset = start_offset + clipboard_selection.len;
12183                            to_insert = &clipboard_text[start_offset..end_offset];
12184                            entire_line = clipboard_selection.is_entire_line;
12185                            start_offset = end_offset + 1;
12186                            original_indent_column = Some(clipboard_selection.first_line_indent);
12187                        } else {
12188                            to_insert = clipboard_text.as_str();
12189                            entire_line = all_selections_were_entire_line;
12190                            original_indent_column = first_selection_indent_column
12191                        }
12192
12193                        // If the corresponding selection was empty when this slice of the
12194                        // clipboard text was written, then the entire line containing the
12195                        // selection was copied. If this selection is also currently empty,
12196                        // then paste the line before the current line of the buffer.
12197                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12198                            let column = selection.start.to_point(&snapshot).column as usize;
12199                            let line_start = selection.start - column;
12200                            line_start..line_start
12201                        } else {
12202                            selection.range()
12203                        };
12204
12205                        edits.push((range, to_insert));
12206                        original_indent_columns.push(original_indent_column);
12207                    }
12208                    drop(snapshot);
12209
12210                    buffer.edit(
12211                        edits,
12212                        if auto_indent_on_paste {
12213                            Some(AutoindentMode::Block {
12214                                original_indent_columns,
12215                            })
12216                        } else {
12217                            None
12218                        },
12219                        cx,
12220                    );
12221                });
12222
12223                let selections = this.selections.all::<usize>(cx);
12224                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12225            } else {
12226                this.insert(&clipboard_text, window, cx);
12227            }
12228        });
12229    }
12230
12231    pub fn diff_clipboard_with_selection(
12232        &mut self,
12233        _: &DiffClipboardWithSelection,
12234        window: &mut Window,
12235        cx: &mut Context<Self>,
12236    ) {
12237        let selections = self.selections.all::<usize>(cx);
12238
12239        if selections.is_empty() {
12240            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12241            return;
12242        };
12243
12244        let clipboard_text = match cx.read_from_clipboard() {
12245            Some(item) => match item.entries().first() {
12246                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12247                _ => None,
12248            },
12249            None => None,
12250        };
12251
12252        let Some(clipboard_text) = clipboard_text else {
12253            log::warn!("Clipboard doesn't contain text.");
12254            return;
12255        };
12256
12257        window.dispatch_action(
12258            Box::new(DiffClipboardWithSelectionData {
12259                clipboard_text,
12260                editor: cx.entity(),
12261            }),
12262            cx,
12263        );
12264    }
12265
12266    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12267        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12268        if let Some(item) = cx.read_from_clipboard() {
12269            let entries = item.entries();
12270
12271            match entries.first() {
12272                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12273                // of all the pasted entries.
12274                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12275                    .do_paste(
12276                        clipboard_string.text(),
12277                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12278                        true,
12279                        window,
12280                        cx,
12281                    ),
12282                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12283            }
12284        }
12285    }
12286
12287    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12288        if self.read_only(cx) {
12289            return;
12290        }
12291
12292        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12293
12294        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12295            if let Some((selections, _)) =
12296                self.selection_history.transaction(transaction_id).cloned()
12297            {
12298                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12299                    s.select_anchors(selections.to_vec());
12300                });
12301            } else {
12302                log::error!(
12303                    "No entry in selection_history found for undo. \
12304                     This may correspond to a bug where undo does not update the selection. \
12305                     If this is occurring, please add details to \
12306                     https://github.com/zed-industries/zed/issues/22692"
12307                );
12308            }
12309            self.request_autoscroll(Autoscroll::fit(), cx);
12310            self.unmark_text(window, cx);
12311            self.refresh_edit_prediction(true, false, window, cx);
12312            cx.emit(EditorEvent::Edited { transaction_id });
12313            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12314        }
12315    }
12316
12317    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12318        if self.read_only(cx) {
12319            return;
12320        }
12321
12322        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12323
12324        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12325            if let Some((_, Some(selections))) =
12326                self.selection_history.transaction(transaction_id).cloned()
12327            {
12328                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12329                    s.select_anchors(selections.to_vec());
12330                });
12331            } else {
12332                log::error!(
12333                    "No entry in selection_history found for redo. \
12334                     This may correspond to a bug where undo does not update the selection. \
12335                     If this is occurring, please add details to \
12336                     https://github.com/zed-industries/zed/issues/22692"
12337                );
12338            }
12339            self.request_autoscroll(Autoscroll::fit(), cx);
12340            self.unmark_text(window, cx);
12341            self.refresh_edit_prediction(true, false, window, cx);
12342            cx.emit(EditorEvent::Edited { transaction_id });
12343        }
12344    }
12345
12346    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12347        self.buffer
12348            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12349    }
12350
12351    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12352        self.buffer
12353            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12354    }
12355
12356    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12357        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12358        self.change_selections(Default::default(), window, cx, |s| {
12359            s.move_with(|map, selection| {
12360                let cursor = if selection.is_empty() {
12361                    movement::left(map, selection.start)
12362                } else {
12363                    selection.start
12364                };
12365                selection.collapse_to(cursor, SelectionGoal::None);
12366            });
12367        })
12368    }
12369
12370    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12371        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12372        self.change_selections(Default::default(), window, cx, |s| {
12373            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12374        })
12375    }
12376
12377    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12378        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12379        self.change_selections(Default::default(), window, cx, |s| {
12380            s.move_with(|map, selection| {
12381                let cursor = if selection.is_empty() {
12382                    movement::right(map, selection.end)
12383                } else {
12384                    selection.end
12385                };
12386                selection.collapse_to(cursor, SelectionGoal::None)
12387            });
12388        })
12389    }
12390
12391    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12392        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12393        self.change_selections(Default::default(), window, cx, |s| {
12394            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12395        })
12396    }
12397
12398    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12399        if self.take_rename(true, window, cx).is_some() {
12400            return;
12401        }
12402
12403        if self.mode.is_single_line() {
12404            cx.propagate();
12405            return;
12406        }
12407
12408        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12409
12410        let text_layout_details = &self.text_layout_details(window);
12411        let selection_count = self.selections.count();
12412        let first_selection = self.selections.first_anchor();
12413
12414        self.change_selections(Default::default(), window, cx, |s| {
12415            s.move_with(|map, selection| {
12416                if !selection.is_empty() {
12417                    selection.goal = SelectionGoal::None;
12418                }
12419                let (cursor, goal) = movement::up(
12420                    map,
12421                    selection.start,
12422                    selection.goal,
12423                    false,
12424                    text_layout_details,
12425                );
12426                selection.collapse_to(cursor, goal);
12427            });
12428        });
12429
12430        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12431        {
12432            cx.propagate();
12433        }
12434    }
12435
12436    pub fn move_up_by_lines(
12437        &mut self,
12438        action: &MoveUpByLines,
12439        window: &mut Window,
12440        cx: &mut Context<Self>,
12441    ) {
12442        if self.take_rename(true, window, cx).is_some() {
12443            return;
12444        }
12445
12446        if self.mode.is_single_line() {
12447            cx.propagate();
12448            return;
12449        }
12450
12451        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12452
12453        let text_layout_details = &self.text_layout_details(window);
12454
12455        self.change_selections(Default::default(), window, cx, |s| {
12456            s.move_with(|map, selection| {
12457                if !selection.is_empty() {
12458                    selection.goal = SelectionGoal::None;
12459                }
12460                let (cursor, goal) = movement::up_by_rows(
12461                    map,
12462                    selection.start,
12463                    action.lines,
12464                    selection.goal,
12465                    false,
12466                    text_layout_details,
12467                );
12468                selection.collapse_to(cursor, goal);
12469            });
12470        })
12471    }
12472
12473    pub fn move_down_by_lines(
12474        &mut self,
12475        action: &MoveDownByLines,
12476        window: &mut Window,
12477        cx: &mut Context<Self>,
12478    ) {
12479        if self.take_rename(true, window, cx).is_some() {
12480            return;
12481        }
12482
12483        if self.mode.is_single_line() {
12484            cx.propagate();
12485            return;
12486        }
12487
12488        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12489
12490        let text_layout_details = &self.text_layout_details(window);
12491
12492        self.change_selections(Default::default(), window, cx, |s| {
12493            s.move_with(|map, selection| {
12494                if !selection.is_empty() {
12495                    selection.goal = SelectionGoal::None;
12496                }
12497                let (cursor, goal) = movement::down_by_rows(
12498                    map,
12499                    selection.start,
12500                    action.lines,
12501                    selection.goal,
12502                    false,
12503                    text_layout_details,
12504                );
12505                selection.collapse_to(cursor, goal);
12506            });
12507        })
12508    }
12509
12510    pub fn select_down_by_lines(
12511        &mut self,
12512        action: &SelectDownByLines,
12513        window: &mut Window,
12514        cx: &mut Context<Self>,
12515    ) {
12516        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12517        let text_layout_details = &self.text_layout_details(window);
12518        self.change_selections(Default::default(), window, cx, |s| {
12519            s.move_heads_with(|map, head, goal| {
12520                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12521            })
12522        })
12523    }
12524
12525    pub fn select_up_by_lines(
12526        &mut self,
12527        action: &SelectUpByLines,
12528        window: &mut Window,
12529        cx: &mut Context<Self>,
12530    ) {
12531        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12532        let text_layout_details = &self.text_layout_details(window);
12533        self.change_selections(Default::default(), window, cx, |s| {
12534            s.move_heads_with(|map, head, goal| {
12535                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12536            })
12537        })
12538    }
12539
12540    pub fn select_page_up(
12541        &mut self,
12542        _: &SelectPageUp,
12543        window: &mut Window,
12544        cx: &mut Context<Self>,
12545    ) {
12546        let Some(row_count) = self.visible_row_count() else {
12547            return;
12548        };
12549
12550        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12551
12552        let text_layout_details = &self.text_layout_details(window);
12553
12554        self.change_selections(Default::default(), window, cx, |s| {
12555            s.move_heads_with(|map, head, goal| {
12556                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12557            })
12558        })
12559    }
12560
12561    pub fn move_page_up(
12562        &mut self,
12563        action: &MovePageUp,
12564        window: &mut Window,
12565        cx: &mut Context<Self>,
12566    ) {
12567        if self.take_rename(true, window, cx).is_some() {
12568            return;
12569        }
12570
12571        if self
12572            .context_menu
12573            .borrow_mut()
12574            .as_mut()
12575            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12576            .unwrap_or(false)
12577        {
12578            return;
12579        }
12580
12581        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12582            cx.propagate();
12583            return;
12584        }
12585
12586        let Some(row_count) = self.visible_row_count() else {
12587            return;
12588        };
12589
12590        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12591
12592        let effects = if action.center_cursor {
12593            SelectionEffects::scroll(Autoscroll::center())
12594        } else {
12595            SelectionEffects::default()
12596        };
12597
12598        let text_layout_details = &self.text_layout_details(window);
12599
12600        self.change_selections(effects, window, cx, |s| {
12601            s.move_with(|map, selection| {
12602                if !selection.is_empty() {
12603                    selection.goal = SelectionGoal::None;
12604                }
12605                let (cursor, goal) = movement::up_by_rows(
12606                    map,
12607                    selection.end,
12608                    row_count,
12609                    selection.goal,
12610                    false,
12611                    text_layout_details,
12612                );
12613                selection.collapse_to(cursor, goal);
12614            });
12615        });
12616    }
12617
12618    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12619        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12620        let text_layout_details = &self.text_layout_details(window);
12621        self.change_selections(Default::default(), window, cx, |s| {
12622            s.move_heads_with(|map, head, goal| {
12623                movement::up(map, head, goal, false, text_layout_details)
12624            })
12625        })
12626    }
12627
12628    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12629        self.take_rename(true, window, cx);
12630
12631        if self.mode.is_single_line() {
12632            cx.propagate();
12633            return;
12634        }
12635
12636        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12637
12638        let text_layout_details = &self.text_layout_details(window);
12639        let selection_count = self.selections.count();
12640        let first_selection = self.selections.first_anchor();
12641
12642        self.change_selections(Default::default(), window, cx, |s| {
12643            s.move_with(|map, selection| {
12644                if !selection.is_empty() {
12645                    selection.goal = SelectionGoal::None;
12646                }
12647                let (cursor, goal) = movement::down(
12648                    map,
12649                    selection.end,
12650                    selection.goal,
12651                    false,
12652                    text_layout_details,
12653                );
12654                selection.collapse_to(cursor, goal);
12655            });
12656        });
12657
12658        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12659        {
12660            cx.propagate();
12661        }
12662    }
12663
12664    pub fn select_page_down(
12665        &mut self,
12666        _: &SelectPageDown,
12667        window: &mut Window,
12668        cx: &mut Context<Self>,
12669    ) {
12670        let Some(row_count) = self.visible_row_count() else {
12671            return;
12672        };
12673
12674        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12675
12676        let text_layout_details = &self.text_layout_details(window);
12677
12678        self.change_selections(Default::default(), window, cx, |s| {
12679            s.move_heads_with(|map, head, goal| {
12680                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12681            })
12682        })
12683    }
12684
12685    pub fn move_page_down(
12686        &mut self,
12687        action: &MovePageDown,
12688        window: &mut Window,
12689        cx: &mut Context<Self>,
12690    ) {
12691        if self.take_rename(true, window, cx).is_some() {
12692            return;
12693        }
12694
12695        if self
12696            .context_menu
12697            .borrow_mut()
12698            .as_mut()
12699            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12700            .unwrap_or(false)
12701        {
12702            return;
12703        }
12704
12705        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12706            cx.propagate();
12707            return;
12708        }
12709
12710        let Some(row_count) = self.visible_row_count() else {
12711            return;
12712        };
12713
12714        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12715
12716        let effects = if action.center_cursor {
12717            SelectionEffects::scroll(Autoscroll::center())
12718        } else {
12719            SelectionEffects::default()
12720        };
12721
12722        let text_layout_details = &self.text_layout_details(window);
12723        self.change_selections(effects, window, cx, |s| {
12724            s.move_with(|map, selection| {
12725                if !selection.is_empty() {
12726                    selection.goal = SelectionGoal::None;
12727                }
12728                let (cursor, goal) = movement::down_by_rows(
12729                    map,
12730                    selection.end,
12731                    row_count,
12732                    selection.goal,
12733                    false,
12734                    text_layout_details,
12735                );
12736                selection.collapse_to(cursor, goal);
12737            });
12738        });
12739    }
12740
12741    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12742        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12743        let text_layout_details = &self.text_layout_details(window);
12744        self.change_selections(Default::default(), window, cx, |s| {
12745            s.move_heads_with(|map, head, goal| {
12746                movement::down(map, head, goal, false, text_layout_details)
12747            })
12748        });
12749    }
12750
12751    pub fn context_menu_first(
12752        &mut self,
12753        _: &ContextMenuFirst,
12754        window: &mut Window,
12755        cx: &mut Context<Self>,
12756    ) {
12757        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12758            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12759        }
12760    }
12761
12762    pub fn context_menu_prev(
12763        &mut self,
12764        _: &ContextMenuPrevious,
12765        window: &mut Window,
12766        cx: &mut Context<Self>,
12767    ) {
12768        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12769            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12770        }
12771    }
12772
12773    pub fn context_menu_next(
12774        &mut self,
12775        _: &ContextMenuNext,
12776        window: &mut Window,
12777        cx: &mut Context<Self>,
12778    ) {
12779        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12780            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12781        }
12782    }
12783
12784    pub fn context_menu_last(
12785        &mut self,
12786        _: &ContextMenuLast,
12787        window: &mut Window,
12788        cx: &mut Context<Self>,
12789    ) {
12790        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12791            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12792        }
12793    }
12794
12795    pub fn signature_help_prev(
12796        &mut self,
12797        _: &SignatureHelpPrevious,
12798        _: &mut Window,
12799        cx: &mut Context<Self>,
12800    ) {
12801        if let Some(popover) = self.signature_help_state.popover_mut() {
12802            if popover.current_signature == 0 {
12803                popover.current_signature = popover.signatures.len() - 1;
12804            } else {
12805                popover.current_signature -= 1;
12806            }
12807            cx.notify();
12808        }
12809    }
12810
12811    pub fn signature_help_next(
12812        &mut self,
12813        _: &SignatureHelpNext,
12814        _: &mut Window,
12815        cx: &mut Context<Self>,
12816    ) {
12817        if let Some(popover) = self.signature_help_state.popover_mut() {
12818            if popover.current_signature + 1 == popover.signatures.len() {
12819                popover.current_signature = 0;
12820            } else {
12821                popover.current_signature += 1;
12822            }
12823            cx.notify();
12824        }
12825    }
12826
12827    pub fn move_to_previous_word_start(
12828        &mut self,
12829        _: &MoveToPreviousWordStart,
12830        window: &mut Window,
12831        cx: &mut Context<Self>,
12832    ) {
12833        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12834        self.change_selections(Default::default(), window, cx, |s| {
12835            s.move_cursors_with(|map, head, _| {
12836                (
12837                    movement::previous_word_start(map, head),
12838                    SelectionGoal::None,
12839                )
12840            });
12841        })
12842    }
12843
12844    pub fn move_to_previous_subword_start(
12845        &mut self,
12846        _: &MoveToPreviousSubwordStart,
12847        window: &mut Window,
12848        cx: &mut Context<Self>,
12849    ) {
12850        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12851        self.change_selections(Default::default(), window, cx, |s| {
12852            s.move_cursors_with(|map, head, _| {
12853                (
12854                    movement::previous_subword_start(map, head),
12855                    SelectionGoal::None,
12856                )
12857            });
12858        })
12859    }
12860
12861    pub fn select_to_previous_word_start(
12862        &mut self,
12863        _: &SelectToPreviousWordStart,
12864        window: &mut Window,
12865        cx: &mut Context<Self>,
12866    ) {
12867        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12868        self.change_selections(Default::default(), window, cx, |s| {
12869            s.move_heads_with(|map, head, _| {
12870                (
12871                    movement::previous_word_start(map, head),
12872                    SelectionGoal::None,
12873                )
12874            });
12875        })
12876    }
12877
12878    pub fn select_to_previous_subword_start(
12879        &mut self,
12880        _: &SelectToPreviousSubwordStart,
12881        window: &mut Window,
12882        cx: &mut Context<Self>,
12883    ) {
12884        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12885        self.change_selections(Default::default(), window, cx, |s| {
12886            s.move_heads_with(|map, head, _| {
12887                (
12888                    movement::previous_subword_start(map, head),
12889                    SelectionGoal::None,
12890                )
12891            });
12892        })
12893    }
12894
12895    pub fn delete_to_previous_word_start(
12896        &mut self,
12897        action: &DeleteToPreviousWordStart,
12898        window: &mut Window,
12899        cx: &mut Context<Self>,
12900    ) {
12901        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12902        self.transact(window, cx, |this, window, cx| {
12903            this.select_autoclose_pair(window, cx);
12904            this.change_selections(Default::default(), window, cx, |s| {
12905                s.move_with(|map, selection| {
12906                    if selection.is_empty() {
12907                        let cursor = if action.ignore_newlines {
12908                            movement::previous_word_start(map, selection.head())
12909                        } else {
12910                            movement::previous_word_start_or_newline(map, selection.head())
12911                        };
12912                        selection.set_head(cursor, SelectionGoal::None);
12913                    }
12914                });
12915            });
12916            this.insert("", window, cx);
12917        });
12918    }
12919
12920    pub fn delete_to_previous_subword_start(
12921        &mut self,
12922        _: &DeleteToPreviousSubwordStart,
12923        window: &mut Window,
12924        cx: &mut Context<Self>,
12925    ) {
12926        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12927        self.transact(window, cx, |this, window, cx| {
12928            this.select_autoclose_pair(window, cx);
12929            this.change_selections(Default::default(), window, cx, |s| {
12930                s.move_with(|map, selection| {
12931                    if selection.is_empty() {
12932                        let cursor = movement::previous_subword_start(map, selection.head());
12933                        selection.set_head(cursor, SelectionGoal::None);
12934                    }
12935                });
12936            });
12937            this.insert("", window, cx);
12938        });
12939    }
12940
12941    pub fn move_to_next_word_end(
12942        &mut self,
12943        _: &MoveToNextWordEnd,
12944        window: &mut Window,
12945        cx: &mut Context<Self>,
12946    ) {
12947        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12948        self.change_selections(Default::default(), window, cx, |s| {
12949            s.move_cursors_with(|map, head, _| {
12950                (movement::next_word_end(map, head), SelectionGoal::None)
12951            });
12952        })
12953    }
12954
12955    pub fn move_to_next_subword_end(
12956        &mut self,
12957        _: &MoveToNextSubwordEnd,
12958        window: &mut Window,
12959        cx: &mut Context<Self>,
12960    ) {
12961        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12962        self.change_selections(Default::default(), window, cx, |s| {
12963            s.move_cursors_with(|map, head, _| {
12964                (movement::next_subword_end(map, head), SelectionGoal::None)
12965            });
12966        })
12967    }
12968
12969    pub fn select_to_next_word_end(
12970        &mut self,
12971        _: &SelectToNextWordEnd,
12972        window: &mut Window,
12973        cx: &mut Context<Self>,
12974    ) {
12975        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12976        self.change_selections(Default::default(), window, cx, |s| {
12977            s.move_heads_with(|map, head, _| {
12978                (movement::next_word_end(map, head), SelectionGoal::None)
12979            });
12980        })
12981    }
12982
12983    pub fn select_to_next_subword_end(
12984        &mut self,
12985        _: &SelectToNextSubwordEnd,
12986        window: &mut Window,
12987        cx: &mut Context<Self>,
12988    ) {
12989        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12990        self.change_selections(Default::default(), window, cx, |s| {
12991            s.move_heads_with(|map, head, _| {
12992                (movement::next_subword_end(map, head), SelectionGoal::None)
12993            });
12994        })
12995    }
12996
12997    pub fn delete_to_next_word_end(
12998        &mut self,
12999        action: &DeleteToNextWordEnd,
13000        window: &mut Window,
13001        cx: &mut Context<Self>,
13002    ) {
13003        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13004        self.transact(window, cx, |this, window, cx| {
13005            this.change_selections(Default::default(), window, cx, |s| {
13006                s.move_with(|map, selection| {
13007                    if selection.is_empty() {
13008                        let cursor = if action.ignore_newlines {
13009                            movement::next_word_end(map, selection.head())
13010                        } else {
13011                            movement::next_word_end_or_newline(map, selection.head())
13012                        };
13013                        selection.set_head(cursor, SelectionGoal::None);
13014                    }
13015                });
13016            });
13017            this.insert("", window, cx);
13018        });
13019    }
13020
13021    pub fn delete_to_next_subword_end(
13022        &mut self,
13023        _: &DeleteToNextSubwordEnd,
13024        window: &mut Window,
13025        cx: &mut Context<Self>,
13026    ) {
13027        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13028        self.transact(window, cx, |this, window, cx| {
13029            this.change_selections(Default::default(), window, cx, |s| {
13030                s.move_with(|map, selection| {
13031                    if selection.is_empty() {
13032                        let cursor = movement::next_subword_end(map, selection.head());
13033                        selection.set_head(cursor, SelectionGoal::None);
13034                    }
13035                });
13036            });
13037            this.insert("", window, cx);
13038        });
13039    }
13040
13041    pub fn move_to_beginning_of_line(
13042        &mut self,
13043        action: &MoveToBeginningOfLine,
13044        window: &mut Window,
13045        cx: &mut Context<Self>,
13046    ) {
13047        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13048        self.change_selections(Default::default(), window, cx, |s| {
13049            s.move_cursors_with(|map, head, _| {
13050                (
13051                    movement::indented_line_beginning(
13052                        map,
13053                        head,
13054                        action.stop_at_soft_wraps,
13055                        action.stop_at_indent,
13056                    ),
13057                    SelectionGoal::None,
13058                )
13059            });
13060        })
13061    }
13062
13063    pub fn select_to_beginning_of_line(
13064        &mut self,
13065        action: &SelectToBeginningOfLine,
13066        window: &mut Window,
13067        cx: &mut Context<Self>,
13068    ) {
13069        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13070        self.change_selections(Default::default(), window, cx, |s| {
13071            s.move_heads_with(|map, head, _| {
13072                (
13073                    movement::indented_line_beginning(
13074                        map,
13075                        head,
13076                        action.stop_at_soft_wraps,
13077                        action.stop_at_indent,
13078                    ),
13079                    SelectionGoal::None,
13080                )
13081            });
13082        });
13083    }
13084
13085    pub fn delete_to_beginning_of_line(
13086        &mut self,
13087        action: &DeleteToBeginningOfLine,
13088        window: &mut Window,
13089        cx: &mut Context<Self>,
13090    ) {
13091        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13092        self.transact(window, cx, |this, window, cx| {
13093            this.change_selections(Default::default(), window, cx, |s| {
13094                s.move_with(|_, selection| {
13095                    selection.reversed = true;
13096                });
13097            });
13098
13099            this.select_to_beginning_of_line(
13100                &SelectToBeginningOfLine {
13101                    stop_at_soft_wraps: false,
13102                    stop_at_indent: action.stop_at_indent,
13103                },
13104                window,
13105                cx,
13106            );
13107            this.backspace(&Backspace, window, cx);
13108        });
13109    }
13110
13111    pub fn move_to_end_of_line(
13112        &mut self,
13113        action: &MoveToEndOfLine,
13114        window: &mut Window,
13115        cx: &mut Context<Self>,
13116    ) {
13117        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13118        self.change_selections(Default::default(), window, cx, |s| {
13119            s.move_cursors_with(|map, head, _| {
13120                (
13121                    movement::line_end(map, head, action.stop_at_soft_wraps),
13122                    SelectionGoal::None,
13123                )
13124            });
13125        })
13126    }
13127
13128    pub fn select_to_end_of_line(
13129        &mut self,
13130        action: &SelectToEndOfLine,
13131        window: &mut Window,
13132        cx: &mut Context<Self>,
13133    ) {
13134        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13135        self.change_selections(Default::default(), window, cx, |s| {
13136            s.move_heads_with(|map, head, _| {
13137                (
13138                    movement::line_end(map, head, action.stop_at_soft_wraps),
13139                    SelectionGoal::None,
13140                )
13141            });
13142        })
13143    }
13144
13145    pub fn delete_to_end_of_line(
13146        &mut self,
13147        _: &DeleteToEndOfLine,
13148        window: &mut Window,
13149        cx: &mut Context<Self>,
13150    ) {
13151        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13152        self.transact(window, cx, |this, window, cx| {
13153            this.select_to_end_of_line(
13154                &SelectToEndOfLine {
13155                    stop_at_soft_wraps: false,
13156                },
13157                window,
13158                cx,
13159            );
13160            this.delete(&Delete, window, cx);
13161        });
13162    }
13163
13164    pub fn cut_to_end_of_line(
13165        &mut self,
13166        _: &CutToEndOfLine,
13167        window: &mut Window,
13168        cx: &mut Context<Self>,
13169    ) {
13170        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13171        self.transact(window, cx, |this, window, cx| {
13172            this.select_to_end_of_line(
13173                &SelectToEndOfLine {
13174                    stop_at_soft_wraps: false,
13175                },
13176                window,
13177                cx,
13178            );
13179            this.cut(&Cut, window, cx);
13180        });
13181    }
13182
13183    pub fn move_to_start_of_paragraph(
13184        &mut self,
13185        _: &MoveToStartOfParagraph,
13186        window: &mut Window,
13187        cx: &mut Context<Self>,
13188    ) {
13189        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13190            cx.propagate();
13191            return;
13192        }
13193        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13194        self.change_selections(Default::default(), window, cx, |s| {
13195            s.move_with(|map, selection| {
13196                selection.collapse_to(
13197                    movement::start_of_paragraph(map, selection.head(), 1),
13198                    SelectionGoal::None,
13199                )
13200            });
13201        })
13202    }
13203
13204    pub fn move_to_end_of_paragraph(
13205        &mut self,
13206        _: &MoveToEndOfParagraph,
13207        window: &mut Window,
13208        cx: &mut Context<Self>,
13209    ) {
13210        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13211            cx.propagate();
13212            return;
13213        }
13214        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13215        self.change_selections(Default::default(), window, cx, |s| {
13216            s.move_with(|map, selection| {
13217                selection.collapse_to(
13218                    movement::end_of_paragraph(map, selection.head(), 1),
13219                    SelectionGoal::None,
13220                )
13221            });
13222        })
13223    }
13224
13225    pub fn select_to_start_of_paragraph(
13226        &mut self,
13227        _: &SelectToStartOfParagraph,
13228        window: &mut Window,
13229        cx: &mut Context<Self>,
13230    ) {
13231        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13232            cx.propagate();
13233            return;
13234        }
13235        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13236        self.change_selections(Default::default(), window, cx, |s| {
13237            s.move_heads_with(|map, head, _| {
13238                (
13239                    movement::start_of_paragraph(map, head, 1),
13240                    SelectionGoal::None,
13241                )
13242            });
13243        })
13244    }
13245
13246    pub fn select_to_end_of_paragraph(
13247        &mut self,
13248        _: &SelectToEndOfParagraph,
13249        window: &mut Window,
13250        cx: &mut Context<Self>,
13251    ) {
13252        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13253            cx.propagate();
13254            return;
13255        }
13256        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13257        self.change_selections(Default::default(), window, cx, |s| {
13258            s.move_heads_with(|map, head, _| {
13259                (
13260                    movement::end_of_paragraph(map, head, 1),
13261                    SelectionGoal::None,
13262                )
13263            });
13264        })
13265    }
13266
13267    pub fn move_to_start_of_excerpt(
13268        &mut self,
13269        _: &MoveToStartOfExcerpt,
13270        window: &mut Window,
13271        cx: &mut Context<Self>,
13272    ) {
13273        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13274            cx.propagate();
13275            return;
13276        }
13277        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13278        self.change_selections(Default::default(), window, cx, |s| {
13279            s.move_with(|map, selection| {
13280                selection.collapse_to(
13281                    movement::start_of_excerpt(
13282                        map,
13283                        selection.head(),
13284                        workspace::searchable::Direction::Prev,
13285                    ),
13286                    SelectionGoal::None,
13287                )
13288            });
13289        })
13290    }
13291
13292    pub fn move_to_start_of_next_excerpt(
13293        &mut self,
13294        _: &MoveToStartOfNextExcerpt,
13295        window: &mut Window,
13296        cx: &mut Context<Self>,
13297    ) {
13298        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13299            cx.propagate();
13300            return;
13301        }
13302
13303        self.change_selections(Default::default(), window, cx, |s| {
13304            s.move_with(|map, selection| {
13305                selection.collapse_to(
13306                    movement::start_of_excerpt(
13307                        map,
13308                        selection.head(),
13309                        workspace::searchable::Direction::Next,
13310                    ),
13311                    SelectionGoal::None,
13312                )
13313            });
13314        })
13315    }
13316
13317    pub fn move_to_end_of_excerpt(
13318        &mut self,
13319        _: &MoveToEndOfExcerpt,
13320        window: &mut Window,
13321        cx: &mut Context<Self>,
13322    ) {
13323        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13324            cx.propagate();
13325            return;
13326        }
13327        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13328        self.change_selections(Default::default(), window, cx, |s| {
13329            s.move_with(|map, selection| {
13330                selection.collapse_to(
13331                    movement::end_of_excerpt(
13332                        map,
13333                        selection.head(),
13334                        workspace::searchable::Direction::Next,
13335                    ),
13336                    SelectionGoal::None,
13337                )
13338            });
13339        })
13340    }
13341
13342    pub fn move_to_end_of_previous_excerpt(
13343        &mut self,
13344        _: &MoveToEndOfPreviousExcerpt,
13345        window: &mut Window,
13346        cx: &mut Context<Self>,
13347    ) {
13348        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13349            cx.propagate();
13350            return;
13351        }
13352        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13353        self.change_selections(Default::default(), window, cx, |s| {
13354            s.move_with(|map, selection| {
13355                selection.collapse_to(
13356                    movement::end_of_excerpt(
13357                        map,
13358                        selection.head(),
13359                        workspace::searchable::Direction::Prev,
13360                    ),
13361                    SelectionGoal::None,
13362                )
13363            });
13364        })
13365    }
13366
13367    pub fn select_to_start_of_excerpt(
13368        &mut self,
13369        _: &SelectToStartOfExcerpt,
13370        window: &mut Window,
13371        cx: &mut Context<Self>,
13372    ) {
13373        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13374            cx.propagate();
13375            return;
13376        }
13377        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13378        self.change_selections(Default::default(), window, cx, |s| {
13379            s.move_heads_with(|map, head, _| {
13380                (
13381                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13382                    SelectionGoal::None,
13383                )
13384            });
13385        })
13386    }
13387
13388    pub fn select_to_start_of_next_excerpt(
13389        &mut self,
13390        _: &SelectToStartOfNextExcerpt,
13391        window: &mut Window,
13392        cx: &mut Context<Self>,
13393    ) {
13394        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13395            cx.propagate();
13396            return;
13397        }
13398        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13399        self.change_selections(Default::default(), window, cx, |s| {
13400            s.move_heads_with(|map, head, _| {
13401                (
13402                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13403                    SelectionGoal::None,
13404                )
13405            });
13406        })
13407    }
13408
13409    pub fn select_to_end_of_excerpt(
13410        &mut self,
13411        _: &SelectToEndOfExcerpt,
13412        window: &mut Window,
13413        cx: &mut Context<Self>,
13414    ) {
13415        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13416            cx.propagate();
13417            return;
13418        }
13419        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13420        self.change_selections(Default::default(), window, cx, |s| {
13421            s.move_heads_with(|map, head, _| {
13422                (
13423                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13424                    SelectionGoal::None,
13425                )
13426            });
13427        })
13428    }
13429
13430    pub fn select_to_end_of_previous_excerpt(
13431        &mut self,
13432        _: &SelectToEndOfPreviousExcerpt,
13433        window: &mut Window,
13434        cx: &mut Context<Self>,
13435    ) {
13436        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13437            cx.propagate();
13438            return;
13439        }
13440        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13441        self.change_selections(Default::default(), window, cx, |s| {
13442            s.move_heads_with(|map, head, _| {
13443                (
13444                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13445                    SelectionGoal::None,
13446                )
13447            });
13448        })
13449    }
13450
13451    pub fn move_to_beginning(
13452        &mut self,
13453        _: &MoveToBeginning,
13454        window: &mut Window,
13455        cx: &mut Context<Self>,
13456    ) {
13457        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13458            cx.propagate();
13459            return;
13460        }
13461        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13462        self.change_selections(Default::default(), window, cx, |s| {
13463            s.select_ranges(vec![0..0]);
13464        });
13465    }
13466
13467    pub fn select_to_beginning(
13468        &mut self,
13469        _: &SelectToBeginning,
13470        window: &mut Window,
13471        cx: &mut Context<Self>,
13472    ) {
13473        let mut selection = self.selections.last::<Point>(cx);
13474        selection.set_head(Point::zero(), SelectionGoal::None);
13475        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13476        self.change_selections(Default::default(), window, cx, |s| {
13477            s.select(vec![selection]);
13478        });
13479    }
13480
13481    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13482        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13483            cx.propagate();
13484            return;
13485        }
13486        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13487        let cursor = self.buffer.read(cx).read(cx).len();
13488        self.change_selections(Default::default(), window, cx, |s| {
13489            s.select_ranges(vec![cursor..cursor])
13490        });
13491    }
13492
13493    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13494        self.nav_history = nav_history;
13495    }
13496
13497    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13498        self.nav_history.as_ref()
13499    }
13500
13501    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13502        self.push_to_nav_history(
13503            self.selections.newest_anchor().head(),
13504            None,
13505            false,
13506            true,
13507            cx,
13508        );
13509    }
13510
13511    fn push_to_nav_history(
13512        &mut self,
13513        cursor_anchor: Anchor,
13514        new_position: Option<Point>,
13515        is_deactivate: bool,
13516        always: bool,
13517        cx: &mut Context<Self>,
13518    ) {
13519        if let Some(nav_history) = self.nav_history.as_mut() {
13520            let buffer = self.buffer.read(cx).read(cx);
13521            let cursor_position = cursor_anchor.to_point(&buffer);
13522            let scroll_state = self.scroll_manager.anchor();
13523            let scroll_top_row = scroll_state.top_row(&buffer);
13524            drop(buffer);
13525
13526            if let Some(new_position) = new_position {
13527                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13528                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13529                    return;
13530                }
13531            }
13532
13533            nav_history.push(
13534                Some(NavigationData {
13535                    cursor_anchor,
13536                    cursor_position,
13537                    scroll_anchor: scroll_state,
13538                    scroll_top_row,
13539                }),
13540                cx,
13541            );
13542            cx.emit(EditorEvent::PushedToNavHistory {
13543                anchor: cursor_anchor,
13544                is_deactivate,
13545            })
13546        }
13547    }
13548
13549    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13550        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13551        let buffer = self.buffer.read(cx).snapshot(cx);
13552        let mut selection = self.selections.first::<usize>(cx);
13553        selection.set_head(buffer.len(), SelectionGoal::None);
13554        self.change_selections(Default::default(), window, cx, |s| {
13555            s.select(vec![selection]);
13556        });
13557    }
13558
13559    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13560        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13561        let end = self.buffer.read(cx).read(cx).len();
13562        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13563            s.select_ranges(vec![0..end]);
13564        });
13565    }
13566
13567    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13568        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13569        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13570        let mut selections = self.selections.all::<Point>(cx);
13571        let max_point = display_map.buffer_snapshot.max_point();
13572        for selection in &mut selections {
13573            let rows = selection.spanned_rows(true, &display_map);
13574            selection.start = Point::new(rows.start.0, 0);
13575            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13576            selection.reversed = false;
13577        }
13578        self.change_selections(Default::default(), window, cx, |s| {
13579            s.select(selections);
13580        });
13581    }
13582
13583    pub fn split_selection_into_lines(
13584        &mut self,
13585        _: &SplitSelectionIntoLines,
13586        window: &mut Window,
13587        cx: &mut Context<Self>,
13588    ) {
13589        let selections = self
13590            .selections
13591            .all::<Point>(cx)
13592            .into_iter()
13593            .map(|selection| selection.start..selection.end)
13594            .collect::<Vec<_>>();
13595        self.unfold_ranges(&selections, true, true, cx);
13596
13597        let mut new_selection_ranges = Vec::new();
13598        {
13599            let buffer = self.buffer.read(cx).read(cx);
13600            for selection in selections {
13601                for row in selection.start.row..selection.end.row {
13602                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13603                    new_selection_ranges.push(cursor..cursor);
13604                }
13605
13606                let is_multiline_selection = selection.start.row != selection.end.row;
13607                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13608                // so this action feels more ergonomic when paired with other selection operations
13609                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13610                if !should_skip_last {
13611                    new_selection_ranges.push(selection.end..selection.end);
13612                }
13613            }
13614        }
13615        self.change_selections(Default::default(), window, cx, |s| {
13616            s.select_ranges(new_selection_ranges);
13617        });
13618    }
13619
13620    pub fn add_selection_above(
13621        &mut self,
13622        _: &AddSelectionAbove,
13623        window: &mut Window,
13624        cx: &mut Context<Self>,
13625    ) {
13626        self.add_selection(true, window, cx);
13627    }
13628
13629    pub fn add_selection_below(
13630        &mut self,
13631        _: &AddSelectionBelow,
13632        window: &mut Window,
13633        cx: &mut Context<Self>,
13634    ) {
13635        self.add_selection(false, window, cx);
13636    }
13637
13638    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13639        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13640
13641        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13642        let all_selections = self.selections.all::<Point>(cx);
13643        let text_layout_details = self.text_layout_details(window);
13644
13645        let (mut columnar_selections, new_selections_to_columnarize) = {
13646            if let Some(state) = self.add_selections_state.as_ref() {
13647                let columnar_selection_ids: HashSet<_> = state
13648                    .groups
13649                    .iter()
13650                    .flat_map(|group| group.stack.iter())
13651                    .copied()
13652                    .collect();
13653
13654                all_selections
13655                    .into_iter()
13656                    .partition(|s| columnar_selection_ids.contains(&s.id))
13657            } else {
13658                (Vec::new(), all_selections)
13659            }
13660        };
13661
13662        let mut state = self
13663            .add_selections_state
13664            .take()
13665            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13666
13667        for selection in new_selections_to_columnarize {
13668            let range = selection.display_range(&display_map).sorted();
13669            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13670            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13671            let positions = start_x.min(end_x)..start_x.max(end_x);
13672            let mut stack = Vec::new();
13673            for row in range.start.row().0..=range.end.row().0 {
13674                if let Some(selection) = self.selections.build_columnar_selection(
13675                    &display_map,
13676                    DisplayRow(row),
13677                    &positions,
13678                    selection.reversed,
13679                    &text_layout_details,
13680                ) {
13681                    stack.push(selection.id);
13682                    columnar_selections.push(selection);
13683                }
13684            }
13685            if !stack.is_empty() {
13686                if above {
13687                    stack.reverse();
13688                }
13689                state.groups.push(AddSelectionsGroup { above, stack });
13690            }
13691        }
13692
13693        let mut final_selections = Vec::new();
13694        let end_row = if above {
13695            DisplayRow(0)
13696        } else {
13697            display_map.max_point().row()
13698        };
13699
13700        let mut last_added_item_per_group = HashMap::default();
13701        for group in state.groups.iter_mut() {
13702            if let Some(last_id) = group.stack.last() {
13703                last_added_item_per_group.insert(*last_id, group);
13704            }
13705        }
13706
13707        for selection in columnar_selections {
13708            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13709                if above == group.above {
13710                    let range = selection.display_range(&display_map).sorted();
13711                    debug_assert_eq!(range.start.row(), range.end.row());
13712                    let mut row = range.start.row();
13713                    let positions =
13714                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13715                            px(start)..px(end)
13716                        } else {
13717                            let start_x =
13718                                display_map.x_for_display_point(range.start, &text_layout_details);
13719                            let end_x =
13720                                display_map.x_for_display_point(range.end, &text_layout_details);
13721                            start_x.min(end_x)..start_x.max(end_x)
13722                        };
13723
13724                    let mut maybe_new_selection = None;
13725                    while row != end_row {
13726                        if above {
13727                            row.0 -= 1;
13728                        } else {
13729                            row.0 += 1;
13730                        }
13731                        if let Some(new_selection) = self.selections.build_columnar_selection(
13732                            &display_map,
13733                            row,
13734                            &positions,
13735                            selection.reversed,
13736                            &text_layout_details,
13737                        ) {
13738                            maybe_new_selection = Some(new_selection);
13739                            break;
13740                        }
13741                    }
13742
13743                    if let Some(new_selection) = maybe_new_selection {
13744                        group.stack.push(new_selection.id);
13745                        if above {
13746                            final_selections.push(new_selection);
13747                            final_selections.push(selection);
13748                        } else {
13749                            final_selections.push(selection);
13750                            final_selections.push(new_selection);
13751                        }
13752                    } else {
13753                        final_selections.push(selection);
13754                    }
13755                } else {
13756                    group.stack.pop();
13757                }
13758            } else {
13759                final_selections.push(selection);
13760            }
13761        }
13762
13763        self.change_selections(Default::default(), window, cx, |s| {
13764            s.select(final_selections);
13765        });
13766
13767        let final_selection_ids: HashSet<_> = self
13768            .selections
13769            .all::<Point>(cx)
13770            .iter()
13771            .map(|s| s.id)
13772            .collect();
13773        state.groups.retain_mut(|group| {
13774            // selections might get merged above so we remove invalid items from stacks
13775            group.stack.retain(|id| final_selection_ids.contains(id));
13776
13777            // single selection in stack can be treated as initial state
13778            group.stack.len() > 1
13779        });
13780
13781        if !state.groups.is_empty() {
13782            self.add_selections_state = Some(state);
13783        }
13784    }
13785
13786    fn select_match_ranges(
13787        &mut self,
13788        range: Range<usize>,
13789        reversed: bool,
13790        replace_newest: bool,
13791        auto_scroll: Option<Autoscroll>,
13792        window: &mut Window,
13793        cx: &mut Context<Editor>,
13794    ) {
13795        self.unfold_ranges(
13796            std::slice::from_ref(&range),
13797            false,
13798            auto_scroll.is_some(),
13799            cx,
13800        );
13801        let effects = if let Some(scroll) = auto_scroll {
13802            SelectionEffects::scroll(scroll)
13803        } else {
13804            SelectionEffects::no_scroll()
13805        };
13806        self.change_selections(effects, window, cx, |s| {
13807            if replace_newest {
13808                s.delete(s.newest_anchor().id);
13809            }
13810            if reversed {
13811                s.insert_range(range.end..range.start);
13812            } else {
13813                s.insert_range(range);
13814            }
13815        });
13816    }
13817
13818    pub fn select_next_match_internal(
13819        &mut self,
13820        display_map: &DisplaySnapshot,
13821        replace_newest: bool,
13822        autoscroll: Option<Autoscroll>,
13823        window: &mut Window,
13824        cx: &mut Context<Self>,
13825    ) -> Result<()> {
13826        let buffer = &display_map.buffer_snapshot;
13827        let mut selections = self.selections.all::<usize>(cx);
13828        if let Some(mut select_next_state) = self.select_next_state.take() {
13829            let query = &select_next_state.query;
13830            if !select_next_state.done {
13831                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13832                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13833                let mut next_selected_range = None;
13834
13835                let bytes_after_last_selection =
13836                    buffer.bytes_in_range(last_selection.end..buffer.len());
13837                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13838                let query_matches = query
13839                    .stream_find_iter(bytes_after_last_selection)
13840                    .map(|result| (last_selection.end, result))
13841                    .chain(
13842                        query
13843                            .stream_find_iter(bytes_before_first_selection)
13844                            .map(|result| (0, result)),
13845                    );
13846
13847                for (start_offset, query_match) in query_matches {
13848                    let query_match = query_match.unwrap(); // can only fail due to I/O
13849                    let offset_range =
13850                        start_offset + query_match.start()..start_offset + query_match.end();
13851
13852                    if !select_next_state.wordwise
13853                        || (!buffer.is_inside_word(offset_range.start, false)
13854                            && !buffer.is_inside_word(offset_range.end, false))
13855                    {
13856                        // TODO: This is n^2, because we might check all the selections
13857                        if !selections
13858                            .iter()
13859                            .any(|selection| selection.range().overlaps(&offset_range))
13860                        {
13861                            next_selected_range = Some(offset_range);
13862                            break;
13863                        }
13864                    }
13865                }
13866
13867                if let Some(next_selected_range) = next_selected_range {
13868                    self.select_match_ranges(
13869                        next_selected_range,
13870                        last_selection.reversed,
13871                        replace_newest,
13872                        autoscroll,
13873                        window,
13874                        cx,
13875                    );
13876                } else {
13877                    select_next_state.done = true;
13878                }
13879            }
13880
13881            self.select_next_state = Some(select_next_state);
13882        } else {
13883            let mut only_carets = true;
13884            let mut same_text_selected = true;
13885            let mut selected_text = None;
13886
13887            let mut selections_iter = selections.iter().peekable();
13888            while let Some(selection) = selections_iter.next() {
13889                if selection.start != selection.end {
13890                    only_carets = false;
13891                }
13892
13893                if same_text_selected {
13894                    if selected_text.is_none() {
13895                        selected_text =
13896                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13897                    }
13898
13899                    if let Some(next_selection) = selections_iter.peek() {
13900                        if next_selection.range().len() == selection.range().len() {
13901                            let next_selected_text = buffer
13902                                .text_for_range(next_selection.range())
13903                                .collect::<String>();
13904                            if Some(next_selected_text) != selected_text {
13905                                same_text_selected = false;
13906                                selected_text = None;
13907                            }
13908                        } else {
13909                            same_text_selected = false;
13910                            selected_text = None;
13911                        }
13912                    }
13913                }
13914            }
13915
13916            if only_carets {
13917                for selection in &mut selections {
13918                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13919                    selection.start = word_range.start;
13920                    selection.end = word_range.end;
13921                    selection.goal = SelectionGoal::None;
13922                    selection.reversed = false;
13923                    self.select_match_ranges(
13924                        selection.start..selection.end,
13925                        selection.reversed,
13926                        replace_newest,
13927                        autoscroll,
13928                        window,
13929                        cx,
13930                    );
13931                }
13932
13933                if selections.len() == 1 {
13934                    let selection = selections
13935                        .last()
13936                        .expect("ensured that there's only one selection");
13937                    let query = buffer
13938                        .text_for_range(selection.start..selection.end)
13939                        .collect::<String>();
13940                    let is_empty = query.is_empty();
13941                    let select_state = SelectNextState {
13942                        query: AhoCorasick::new(&[query])?,
13943                        wordwise: true,
13944                        done: is_empty,
13945                    };
13946                    self.select_next_state = Some(select_state);
13947                } else {
13948                    self.select_next_state = None;
13949                }
13950            } else if let Some(selected_text) = selected_text {
13951                self.select_next_state = Some(SelectNextState {
13952                    query: AhoCorasick::new(&[selected_text])?,
13953                    wordwise: false,
13954                    done: false,
13955                });
13956                self.select_next_match_internal(
13957                    display_map,
13958                    replace_newest,
13959                    autoscroll,
13960                    window,
13961                    cx,
13962                )?;
13963            }
13964        }
13965        Ok(())
13966    }
13967
13968    pub fn select_all_matches(
13969        &mut self,
13970        _action: &SelectAllMatches,
13971        window: &mut Window,
13972        cx: &mut Context<Self>,
13973    ) -> Result<()> {
13974        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13975
13976        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13977
13978        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13979        let Some(select_next_state) = self.select_next_state.as_mut() else {
13980            return Ok(());
13981        };
13982        if select_next_state.done {
13983            return Ok(());
13984        }
13985
13986        let mut new_selections = Vec::new();
13987
13988        let reversed = self.selections.oldest::<usize>(cx).reversed;
13989        let buffer = &display_map.buffer_snapshot;
13990        let query_matches = select_next_state
13991            .query
13992            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13993
13994        for query_match in query_matches.into_iter() {
13995            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13996            let offset_range = if reversed {
13997                query_match.end()..query_match.start()
13998            } else {
13999                query_match.start()..query_match.end()
14000            };
14001
14002            if !select_next_state.wordwise
14003                || (!buffer.is_inside_word(offset_range.start, false)
14004                    && !buffer.is_inside_word(offset_range.end, false))
14005            {
14006                new_selections.push(offset_range.start..offset_range.end);
14007            }
14008        }
14009
14010        select_next_state.done = true;
14011
14012        if new_selections.is_empty() {
14013            log::error!("bug: new_selections is empty in select_all_matches");
14014            return Ok(());
14015        }
14016
14017        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14018        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14019            selections.select_ranges(new_selections)
14020        });
14021
14022        Ok(())
14023    }
14024
14025    pub fn select_next(
14026        &mut self,
14027        action: &SelectNext,
14028        window: &mut Window,
14029        cx: &mut Context<Self>,
14030    ) -> Result<()> {
14031        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14032        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14033        self.select_next_match_internal(
14034            &display_map,
14035            action.replace_newest,
14036            Some(Autoscroll::newest()),
14037            window,
14038            cx,
14039        )?;
14040        Ok(())
14041    }
14042
14043    pub fn select_previous(
14044        &mut self,
14045        action: &SelectPrevious,
14046        window: &mut Window,
14047        cx: &mut Context<Self>,
14048    ) -> Result<()> {
14049        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14050        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14051        let buffer = &display_map.buffer_snapshot;
14052        let mut selections = self.selections.all::<usize>(cx);
14053        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14054            let query = &select_prev_state.query;
14055            if !select_prev_state.done {
14056                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14057                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14058                let mut next_selected_range = None;
14059                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14060                let bytes_before_last_selection =
14061                    buffer.reversed_bytes_in_range(0..last_selection.start);
14062                let bytes_after_first_selection =
14063                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14064                let query_matches = query
14065                    .stream_find_iter(bytes_before_last_selection)
14066                    .map(|result| (last_selection.start, result))
14067                    .chain(
14068                        query
14069                            .stream_find_iter(bytes_after_first_selection)
14070                            .map(|result| (buffer.len(), result)),
14071                    );
14072                for (end_offset, query_match) in query_matches {
14073                    let query_match = query_match.unwrap(); // can only fail due to I/O
14074                    let offset_range =
14075                        end_offset - query_match.end()..end_offset - query_match.start();
14076
14077                    if !select_prev_state.wordwise
14078                        || (!buffer.is_inside_word(offset_range.start, false)
14079                            && !buffer.is_inside_word(offset_range.end, false))
14080                    {
14081                        next_selected_range = Some(offset_range);
14082                        break;
14083                    }
14084                }
14085
14086                if let Some(next_selected_range) = next_selected_range {
14087                    self.select_match_ranges(
14088                        next_selected_range,
14089                        last_selection.reversed,
14090                        action.replace_newest,
14091                        Some(Autoscroll::newest()),
14092                        window,
14093                        cx,
14094                    );
14095                } else {
14096                    select_prev_state.done = true;
14097                }
14098            }
14099
14100            self.select_prev_state = Some(select_prev_state);
14101        } else {
14102            let mut only_carets = true;
14103            let mut same_text_selected = true;
14104            let mut selected_text = None;
14105
14106            let mut selections_iter = selections.iter().peekable();
14107            while let Some(selection) = selections_iter.next() {
14108                if selection.start != selection.end {
14109                    only_carets = false;
14110                }
14111
14112                if same_text_selected {
14113                    if selected_text.is_none() {
14114                        selected_text =
14115                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14116                    }
14117
14118                    if let Some(next_selection) = selections_iter.peek() {
14119                        if next_selection.range().len() == selection.range().len() {
14120                            let next_selected_text = buffer
14121                                .text_for_range(next_selection.range())
14122                                .collect::<String>();
14123                            if Some(next_selected_text) != selected_text {
14124                                same_text_selected = false;
14125                                selected_text = None;
14126                            }
14127                        } else {
14128                            same_text_selected = false;
14129                            selected_text = None;
14130                        }
14131                    }
14132                }
14133            }
14134
14135            if only_carets {
14136                for selection in &mut selections {
14137                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14138                    selection.start = word_range.start;
14139                    selection.end = word_range.end;
14140                    selection.goal = SelectionGoal::None;
14141                    selection.reversed = false;
14142                    self.select_match_ranges(
14143                        selection.start..selection.end,
14144                        selection.reversed,
14145                        action.replace_newest,
14146                        Some(Autoscroll::newest()),
14147                        window,
14148                        cx,
14149                    );
14150                }
14151                if selections.len() == 1 {
14152                    let selection = selections
14153                        .last()
14154                        .expect("ensured that there's only one selection");
14155                    let query = buffer
14156                        .text_for_range(selection.start..selection.end)
14157                        .collect::<String>();
14158                    let is_empty = query.is_empty();
14159                    let select_state = SelectNextState {
14160                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14161                        wordwise: true,
14162                        done: is_empty,
14163                    };
14164                    self.select_prev_state = Some(select_state);
14165                } else {
14166                    self.select_prev_state = None;
14167                }
14168            } else if let Some(selected_text) = selected_text {
14169                self.select_prev_state = Some(SelectNextState {
14170                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14171                    wordwise: false,
14172                    done: false,
14173                });
14174                self.select_previous(action, window, cx)?;
14175            }
14176        }
14177        Ok(())
14178    }
14179
14180    pub fn find_next_match(
14181        &mut self,
14182        _: &FindNextMatch,
14183        window: &mut Window,
14184        cx: &mut Context<Self>,
14185    ) -> Result<()> {
14186        let selections = self.selections.disjoint_anchors();
14187        match selections.first() {
14188            Some(first) if selections.len() >= 2 => {
14189                self.change_selections(Default::default(), window, cx, |s| {
14190                    s.select_ranges([first.range()]);
14191                });
14192            }
14193            _ => self.select_next(
14194                &SelectNext {
14195                    replace_newest: true,
14196                },
14197                window,
14198                cx,
14199            )?,
14200        }
14201        Ok(())
14202    }
14203
14204    pub fn find_previous_match(
14205        &mut self,
14206        _: &FindPreviousMatch,
14207        window: &mut Window,
14208        cx: &mut Context<Self>,
14209    ) -> Result<()> {
14210        let selections = self.selections.disjoint_anchors();
14211        match selections.last() {
14212            Some(last) if selections.len() >= 2 => {
14213                self.change_selections(Default::default(), window, cx, |s| {
14214                    s.select_ranges([last.range()]);
14215                });
14216            }
14217            _ => self.select_previous(
14218                &SelectPrevious {
14219                    replace_newest: true,
14220                },
14221                window,
14222                cx,
14223            )?,
14224        }
14225        Ok(())
14226    }
14227
14228    pub fn toggle_comments(
14229        &mut self,
14230        action: &ToggleComments,
14231        window: &mut Window,
14232        cx: &mut Context<Self>,
14233    ) {
14234        if self.read_only(cx) {
14235            return;
14236        }
14237        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14238        let text_layout_details = &self.text_layout_details(window);
14239        self.transact(window, cx, |this, window, cx| {
14240            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14241            let mut edits = Vec::new();
14242            let mut selection_edit_ranges = Vec::new();
14243            let mut last_toggled_row = None;
14244            let snapshot = this.buffer.read(cx).read(cx);
14245            let empty_str: Arc<str> = Arc::default();
14246            let mut suffixes_inserted = Vec::new();
14247            let ignore_indent = action.ignore_indent;
14248
14249            fn comment_prefix_range(
14250                snapshot: &MultiBufferSnapshot,
14251                row: MultiBufferRow,
14252                comment_prefix: &str,
14253                comment_prefix_whitespace: &str,
14254                ignore_indent: bool,
14255            ) -> Range<Point> {
14256                let indent_size = if ignore_indent {
14257                    0
14258                } else {
14259                    snapshot.indent_size_for_line(row).len
14260                };
14261
14262                let start = Point::new(row.0, indent_size);
14263
14264                let mut line_bytes = snapshot
14265                    .bytes_in_range(start..snapshot.max_point())
14266                    .flatten()
14267                    .copied();
14268
14269                // If this line currently begins with the line comment prefix, then record
14270                // the range containing the prefix.
14271                if line_bytes
14272                    .by_ref()
14273                    .take(comment_prefix.len())
14274                    .eq(comment_prefix.bytes())
14275                {
14276                    // Include any whitespace that matches the comment prefix.
14277                    let matching_whitespace_len = line_bytes
14278                        .zip(comment_prefix_whitespace.bytes())
14279                        .take_while(|(a, b)| a == b)
14280                        .count() as u32;
14281                    let end = Point::new(
14282                        start.row,
14283                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14284                    );
14285                    start..end
14286                } else {
14287                    start..start
14288                }
14289            }
14290
14291            fn comment_suffix_range(
14292                snapshot: &MultiBufferSnapshot,
14293                row: MultiBufferRow,
14294                comment_suffix: &str,
14295                comment_suffix_has_leading_space: bool,
14296            ) -> Range<Point> {
14297                let end = Point::new(row.0, snapshot.line_len(row));
14298                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14299
14300                let mut line_end_bytes = snapshot
14301                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14302                    .flatten()
14303                    .copied();
14304
14305                let leading_space_len = if suffix_start_column > 0
14306                    && line_end_bytes.next() == Some(b' ')
14307                    && comment_suffix_has_leading_space
14308                {
14309                    1
14310                } else {
14311                    0
14312                };
14313
14314                // If this line currently begins with the line comment prefix, then record
14315                // the range containing the prefix.
14316                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14317                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14318                    start..end
14319                } else {
14320                    end..end
14321                }
14322            }
14323
14324            // TODO: Handle selections that cross excerpts
14325            for selection in &mut selections {
14326                let start_column = snapshot
14327                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14328                    .len;
14329                let language = if let Some(language) =
14330                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14331                {
14332                    language
14333                } else {
14334                    continue;
14335                };
14336
14337                selection_edit_ranges.clear();
14338
14339                // If multiple selections contain a given row, avoid processing that
14340                // row more than once.
14341                let mut start_row = MultiBufferRow(selection.start.row);
14342                if last_toggled_row == Some(start_row) {
14343                    start_row = start_row.next_row();
14344                }
14345                let end_row =
14346                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14347                        MultiBufferRow(selection.end.row - 1)
14348                    } else {
14349                        MultiBufferRow(selection.end.row)
14350                    };
14351                last_toggled_row = Some(end_row);
14352
14353                if start_row > end_row {
14354                    continue;
14355                }
14356
14357                // If the language has line comments, toggle those.
14358                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14359
14360                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14361                if ignore_indent {
14362                    full_comment_prefixes = full_comment_prefixes
14363                        .into_iter()
14364                        .map(|s| Arc::from(s.trim_end()))
14365                        .collect();
14366                }
14367
14368                if !full_comment_prefixes.is_empty() {
14369                    let first_prefix = full_comment_prefixes
14370                        .first()
14371                        .expect("prefixes is non-empty");
14372                    let prefix_trimmed_lengths = full_comment_prefixes
14373                        .iter()
14374                        .map(|p| p.trim_end_matches(' ').len())
14375                        .collect::<SmallVec<[usize; 4]>>();
14376
14377                    let mut all_selection_lines_are_comments = true;
14378
14379                    for row in start_row.0..=end_row.0 {
14380                        let row = MultiBufferRow(row);
14381                        if start_row < end_row && snapshot.is_line_blank(row) {
14382                            continue;
14383                        }
14384
14385                        let prefix_range = full_comment_prefixes
14386                            .iter()
14387                            .zip(prefix_trimmed_lengths.iter().copied())
14388                            .map(|(prefix, trimmed_prefix_len)| {
14389                                comment_prefix_range(
14390                                    snapshot.deref(),
14391                                    row,
14392                                    &prefix[..trimmed_prefix_len],
14393                                    &prefix[trimmed_prefix_len..],
14394                                    ignore_indent,
14395                                )
14396                            })
14397                            .max_by_key(|range| range.end.column - range.start.column)
14398                            .expect("prefixes is non-empty");
14399
14400                        if prefix_range.is_empty() {
14401                            all_selection_lines_are_comments = false;
14402                        }
14403
14404                        selection_edit_ranges.push(prefix_range);
14405                    }
14406
14407                    if all_selection_lines_are_comments {
14408                        edits.extend(
14409                            selection_edit_ranges
14410                                .iter()
14411                                .cloned()
14412                                .map(|range| (range, empty_str.clone())),
14413                        );
14414                    } else {
14415                        let min_column = selection_edit_ranges
14416                            .iter()
14417                            .map(|range| range.start.column)
14418                            .min()
14419                            .unwrap_or(0);
14420                        edits.extend(selection_edit_ranges.iter().map(|range| {
14421                            let position = Point::new(range.start.row, min_column);
14422                            (position..position, first_prefix.clone())
14423                        }));
14424                    }
14425                } else if let Some(BlockCommentConfig {
14426                    start: full_comment_prefix,
14427                    end: comment_suffix,
14428                    ..
14429                }) = language.block_comment()
14430                {
14431                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14432                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14433                    let prefix_range = comment_prefix_range(
14434                        snapshot.deref(),
14435                        start_row,
14436                        comment_prefix,
14437                        comment_prefix_whitespace,
14438                        ignore_indent,
14439                    );
14440                    let suffix_range = comment_suffix_range(
14441                        snapshot.deref(),
14442                        end_row,
14443                        comment_suffix.trim_start_matches(' '),
14444                        comment_suffix.starts_with(' '),
14445                    );
14446
14447                    if prefix_range.is_empty() || suffix_range.is_empty() {
14448                        edits.push((
14449                            prefix_range.start..prefix_range.start,
14450                            full_comment_prefix.clone(),
14451                        ));
14452                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14453                        suffixes_inserted.push((end_row, comment_suffix.len()));
14454                    } else {
14455                        edits.push((prefix_range, empty_str.clone()));
14456                        edits.push((suffix_range, empty_str.clone()));
14457                    }
14458                } else {
14459                    continue;
14460                }
14461            }
14462
14463            drop(snapshot);
14464            this.buffer.update(cx, |buffer, cx| {
14465                buffer.edit(edits, None, cx);
14466            });
14467
14468            // Adjust selections so that they end before any comment suffixes that
14469            // were inserted.
14470            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14471            let mut selections = this.selections.all::<Point>(cx);
14472            let snapshot = this.buffer.read(cx).read(cx);
14473            for selection in &mut selections {
14474                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14475                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14476                        Ordering::Less => {
14477                            suffixes_inserted.next();
14478                            continue;
14479                        }
14480                        Ordering::Greater => break,
14481                        Ordering::Equal => {
14482                            if selection.end.column == snapshot.line_len(row) {
14483                                if selection.is_empty() {
14484                                    selection.start.column -= suffix_len as u32;
14485                                }
14486                                selection.end.column -= suffix_len as u32;
14487                            }
14488                            break;
14489                        }
14490                    }
14491                }
14492            }
14493
14494            drop(snapshot);
14495            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14496
14497            let selections = this.selections.all::<Point>(cx);
14498            let selections_on_single_row = selections.windows(2).all(|selections| {
14499                selections[0].start.row == selections[1].start.row
14500                    && selections[0].end.row == selections[1].end.row
14501                    && selections[0].start.row == selections[0].end.row
14502            });
14503            let selections_selecting = selections
14504                .iter()
14505                .any(|selection| selection.start != selection.end);
14506            let advance_downwards = action.advance_downwards
14507                && selections_on_single_row
14508                && !selections_selecting
14509                && !matches!(this.mode, EditorMode::SingleLine { .. });
14510
14511            if advance_downwards {
14512                let snapshot = this.buffer.read(cx).snapshot(cx);
14513
14514                this.change_selections(Default::default(), window, cx, |s| {
14515                    s.move_cursors_with(|display_snapshot, display_point, _| {
14516                        let mut point = display_point.to_point(display_snapshot);
14517                        point.row += 1;
14518                        point = snapshot.clip_point(point, Bias::Left);
14519                        let display_point = point.to_display_point(display_snapshot);
14520                        let goal = SelectionGoal::HorizontalPosition(
14521                            display_snapshot
14522                                .x_for_display_point(display_point, text_layout_details)
14523                                .into(),
14524                        );
14525                        (display_point, goal)
14526                    })
14527                });
14528            }
14529        });
14530    }
14531
14532    pub fn select_enclosing_symbol(
14533        &mut self,
14534        _: &SelectEnclosingSymbol,
14535        window: &mut Window,
14536        cx: &mut Context<Self>,
14537    ) {
14538        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14539
14540        let buffer = self.buffer.read(cx).snapshot(cx);
14541        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14542
14543        fn update_selection(
14544            selection: &Selection<usize>,
14545            buffer_snap: &MultiBufferSnapshot,
14546        ) -> Option<Selection<usize>> {
14547            let cursor = selection.head();
14548            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14549            for symbol in symbols.iter().rev() {
14550                let start = symbol.range.start.to_offset(buffer_snap);
14551                let end = symbol.range.end.to_offset(buffer_snap);
14552                let new_range = start..end;
14553                if start < selection.start || end > selection.end {
14554                    return Some(Selection {
14555                        id: selection.id,
14556                        start: new_range.start,
14557                        end: new_range.end,
14558                        goal: SelectionGoal::None,
14559                        reversed: selection.reversed,
14560                    });
14561                }
14562            }
14563            None
14564        }
14565
14566        let mut selected_larger_symbol = false;
14567        let new_selections = old_selections
14568            .iter()
14569            .map(|selection| match update_selection(selection, &buffer) {
14570                Some(new_selection) => {
14571                    if new_selection.range() != selection.range() {
14572                        selected_larger_symbol = true;
14573                    }
14574                    new_selection
14575                }
14576                None => selection.clone(),
14577            })
14578            .collect::<Vec<_>>();
14579
14580        if selected_larger_symbol {
14581            self.change_selections(Default::default(), window, cx, |s| {
14582                s.select(new_selections);
14583            });
14584        }
14585    }
14586
14587    pub fn select_larger_syntax_node(
14588        &mut self,
14589        _: &SelectLargerSyntaxNode,
14590        window: &mut Window,
14591        cx: &mut Context<Self>,
14592    ) {
14593        let Some(visible_row_count) = self.visible_row_count() else {
14594            return;
14595        };
14596        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14597        if old_selections.is_empty() {
14598            return;
14599        }
14600
14601        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14602
14603        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14604        let buffer = self.buffer.read(cx).snapshot(cx);
14605
14606        let mut selected_larger_node = false;
14607        let mut new_selections = old_selections
14608            .iter()
14609            .map(|selection| {
14610                let old_range = selection.start..selection.end;
14611
14612                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14613                    // manually select word at selection
14614                    if ["string_content", "inline"].contains(&node.kind()) {
14615                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14616                        // ignore if word is already selected
14617                        if !word_range.is_empty() && old_range != word_range {
14618                            let (last_word_range, _) =
14619                                buffer.surrounding_word(old_range.end, false);
14620                            // only select word if start and end point belongs to same word
14621                            if word_range == last_word_range {
14622                                selected_larger_node = true;
14623                                return Selection {
14624                                    id: selection.id,
14625                                    start: word_range.start,
14626                                    end: word_range.end,
14627                                    goal: SelectionGoal::None,
14628                                    reversed: selection.reversed,
14629                                };
14630                            }
14631                        }
14632                    }
14633                }
14634
14635                let mut new_range = old_range.clone();
14636                while let Some((_node, containing_range)) =
14637                    buffer.syntax_ancestor(new_range.clone())
14638                {
14639                    new_range = match containing_range {
14640                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14641                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14642                    };
14643                    if !display_map.intersects_fold(new_range.start)
14644                        && !display_map.intersects_fold(new_range.end)
14645                    {
14646                        break;
14647                    }
14648                }
14649
14650                selected_larger_node |= new_range != old_range;
14651                Selection {
14652                    id: selection.id,
14653                    start: new_range.start,
14654                    end: new_range.end,
14655                    goal: SelectionGoal::None,
14656                    reversed: selection.reversed,
14657                }
14658            })
14659            .collect::<Vec<_>>();
14660
14661        if !selected_larger_node {
14662            return; // don't put this call in the history
14663        }
14664
14665        // scroll based on transformation done to the last selection created by the user
14666        let (last_old, last_new) = old_selections
14667            .last()
14668            .zip(new_selections.last().cloned())
14669            .expect("old_selections isn't empty");
14670
14671        // revert selection
14672        let is_selection_reversed = {
14673            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14674            new_selections.last_mut().expect("checked above").reversed =
14675                should_newest_selection_be_reversed;
14676            should_newest_selection_be_reversed
14677        };
14678
14679        if selected_larger_node {
14680            self.select_syntax_node_history.disable_clearing = true;
14681            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14682                s.select(new_selections.clone());
14683            });
14684            self.select_syntax_node_history.disable_clearing = false;
14685        }
14686
14687        let start_row = last_new.start.to_display_point(&display_map).row().0;
14688        let end_row = last_new.end.to_display_point(&display_map).row().0;
14689        let selection_height = end_row - start_row + 1;
14690        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14691
14692        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14693        let scroll_behavior = if fits_on_the_screen {
14694            self.request_autoscroll(Autoscroll::fit(), cx);
14695            SelectSyntaxNodeScrollBehavior::FitSelection
14696        } else if is_selection_reversed {
14697            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14698            SelectSyntaxNodeScrollBehavior::CursorTop
14699        } else {
14700            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14701            SelectSyntaxNodeScrollBehavior::CursorBottom
14702        };
14703
14704        self.select_syntax_node_history.push((
14705            old_selections,
14706            scroll_behavior,
14707            is_selection_reversed,
14708        ));
14709    }
14710
14711    pub fn select_smaller_syntax_node(
14712        &mut self,
14713        _: &SelectSmallerSyntaxNode,
14714        window: &mut Window,
14715        cx: &mut Context<Self>,
14716    ) {
14717        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14718
14719        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14720            self.select_syntax_node_history.pop()
14721        {
14722            if let Some(selection) = selections.last_mut() {
14723                selection.reversed = is_selection_reversed;
14724            }
14725
14726            self.select_syntax_node_history.disable_clearing = true;
14727            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14728                s.select(selections.to_vec());
14729            });
14730            self.select_syntax_node_history.disable_clearing = false;
14731
14732            match scroll_behavior {
14733                SelectSyntaxNodeScrollBehavior::CursorTop => {
14734                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14735                }
14736                SelectSyntaxNodeScrollBehavior::FitSelection => {
14737                    self.request_autoscroll(Autoscroll::fit(), cx);
14738                }
14739                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14740                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14741                }
14742            }
14743        }
14744    }
14745
14746    pub fn unwrap_syntax_node(
14747        &mut self,
14748        _: &UnwrapSyntaxNode,
14749        window: &mut Window,
14750        cx: &mut Context<Self>,
14751    ) {
14752        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14753
14754        let buffer = self.buffer.read(cx).snapshot(cx);
14755        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14756
14757        let edits = old_selections
14758            .iter()
14759            // only consider the first selection for now
14760            .take(1)
14761            .map(|selection| {
14762                // Only requires two branches once if-let-chains stabilize (#53667)
14763                let selection_range = if !selection.is_empty() {
14764                    selection.range()
14765                } else if let Some((_, ancestor_range)) =
14766                    buffer.syntax_ancestor(selection.start..selection.end)
14767                {
14768                    match ancestor_range {
14769                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14770                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14771                    }
14772                } else {
14773                    selection.range()
14774                };
14775
14776                let mut new_range = selection_range.clone();
14777                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(new_range.clone()) {
14778                    new_range = match ancestor_range {
14779                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14780                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14781                    };
14782                    if new_range.start < selection_range.start
14783                        || new_range.end > selection_range.end
14784                    {
14785                        break;
14786                    }
14787                }
14788
14789                (selection, selection_range, new_range)
14790            })
14791            .collect::<Vec<_>>();
14792
14793        self.transact(window, cx, |editor, window, cx| {
14794            for (_, child, parent) in &edits {
14795                let text = buffer.text_for_range(child.clone()).collect::<String>();
14796                editor.replace_text_in_range(Some(parent.clone()), &text, window, cx);
14797            }
14798
14799            editor.change_selections(
14800                SelectionEffects::scroll(Autoscroll::fit()),
14801                window,
14802                cx,
14803                |s| {
14804                    s.select(
14805                        edits
14806                            .iter()
14807                            .map(|(s, old, new)| Selection {
14808                                id: s.id,
14809                                start: new.start,
14810                                end: new.start + old.len(),
14811                                goal: SelectionGoal::None,
14812                                reversed: s.reversed,
14813                            })
14814                            .collect(),
14815                    );
14816                },
14817            );
14818        });
14819    }
14820
14821    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14822        if !EditorSettings::get_global(cx).gutter.runnables {
14823            self.clear_tasks();
14824            return Task::ready(());
14825        }
14826        let project = self.project.as_ref().map(Entity::downgrade);
14827        let task_sources = self.lsp_task_sources(cx);
14828        let multi_buffer = self.buffer.downgrade();
14829        cx.spawn_in(window, async move |editor, cx| {
14830            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14831            let Some(project) = project.and_then(|p| p.upgrade()) else {
14832                return;
14833            };
14834            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14835                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14836            }) else {
14837                return;
14838            };
14839
14840            let hide_runnables = project
14841                .update(cx, |project, cx| {
14842                    // Do not display any test indicators in non-dev server remote projects.
14843                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14844                })
14845                .unwrap_or(true);
14846            if hide_runnables {
14847                return;
14848            }
14849            let new_rows =
14850                cx.background_spawn({
14851                    let snapshot = display_snapshot.clone();
14852                    async move {
14853                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14854                    }
14855                })
14856                    .await;
14857            let Ok(lsp_tasks) =
14858                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14859            else {
14860                return;
14861            };
14862            let lsp_tasks = lsp_tasks.await;
14863
14864            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14865                lsp_tasks
14866                    .into_iter()
14867                    .flat_map(|(kind, tasks)| {
14868                        tasks.into_iter().filter_map(move |(location, task)| {
14869                            Some((kind.clone(), location?, task))
14870                        })
14871                    })
14872                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14873                        let buffer = location.target.buffer;
14874                        let buffer_snapshot = buffer.read(cx).snapshot();
14875                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14876                            |(excerpt_id, snapshot, _)| {
14877                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14878                                    display_snapshot
14879                                        .buffer_snapshot
14880                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14881                                } else {
14882                                    None
14883                                }
14884                            },
14885                        );
14886                        if let Some(offset) = offset {
14887                            let task_buffer_range =
14888                                location.target.range.to_point(&buffer_snapshot);
14889                            let context_buffer_range =
14890                                task_buffer_range.to_offset(&buffer_snapshot);
14891                            let context_range = BufferOffset(context_buffer_range.start)
14892                                ..BufferOffset(context_buffer_range.end);
14893
14894                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14895                                .or_insert_with(|| RunnableTasks {
14896                                    templates: Vec::new(),
14897                                    offset,
14898                                    column: task_buffer_range.start.column,
14899                                    extra_variables: HashMap::default(),
14900                                    context_range,
14901                                })
14902                                .templates
14903                                .push((kind, task.original_task().clone()));
14904                        }
14905
14906                        acc
14907                    })
14908            }) else {
14909                return;
14910            };
14911
14912            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14913                buffer.language_settings(cx).tasks.prefer_lsp
14914            }) else {
14915                return;
14916            };
14917
14918            let rows = Self::runnable_rows(
14919                project,
14920                display_snapshot,
14921                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14922                new_rows,
14923                cx.clone(),
14924            )
14925            .await;
14926            editor
14927                .update(cx, |editor, _| {
14928                    editor.clear_tasks();
14929                    for (key, mut value) in rows {
14930                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14931                            value.templates.extend(lsp_tasks.templates);
14932                        }
14933
14934                        editor.insert_tasks(key, value);
14935                    }
14936                    for (key, value) in lsp_tasks_by_rows {
14937                        editor.insert_tasks(key, value);
14938                    }
14939                })
14940                .ok();
14941        })
14942    }
14943    fn fetch_runnable_ranges(
14944        snapshot: &DisplaySnapshot,
14945        range: Range<Anchor>,
14946    ) -> Vec<language::RunnableRange> {
14947        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14948    }
14949
14950    fn runnable_rows(
14951        project: Entity<Project>,
14952        snapshot: DisplaySnapshot,
14953        prefer_lsp: bool,
14954        runnable_ranges: Vec<RunnableRange>,
14955        cx: AsyncWindowContext,
14956    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14957        cx.spawn(async move |cx| {
14958            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14959            for mut runnable in runnable_ranges {
14960                let Some(tasks) = cx
14961                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14962                    .ok()
14963                else {
14964                    continue;
14965                };
14966                let mut tasks = tasks.await;
14967
14968                if prefer_lsp {
14969                    tasks.retain(|(task_kind, _)| {
14970                        !matches!(task_kind, TaskSourceKind::Language { .. })
14971                    });
14972                }
14973                if tasks.is_empty() {
14974                    continue;
14975                }
14976
14977                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14978                let Some(row) = snapshot
14979                    .buffer_snapshot
14980                    .buffer_line_for_row(MultiBufferRow(point.row))
14981                    .map(|(_, range)| range.start.row)
14982                else {
14983                    continue;
14984                };
14985
14986                let context_range =
14987                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14988                runnable_rows.push((
14989                    (runnable.buffer_id, row),
14990                    RunnableTasks {
14991                        templates: tasks,
14992                        offset: snapshot
14993                            .buffer_snapshot
14994                            .anchor_before(runnable.run_range.start),
14995                        context_range,
14996                        column: point.column,
14997                        extra_variables: runnable.extra_captures,
14998                    },
14999                ));
15000            }
15001            runnable_rows
15002        })
15003    }
15004
15005    fn templates_with_tags(
15006        project: &Entity<Project>,
15007        runnable: &mut Runnable,
15008        cx: &mut App,
15009    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15010        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15011            let (worktree_id, file) = project
15012                .buffer_for_id(runnable.buffer, cx)
15013                .and_then(|buffer| buffer.read(cx).file())
15014                .map(|file| (file.worktree_id(cx), file.clone()))
15015                .unzip();
15016
15017            (
15018                project.task_store().read(cx).task_inventory().cloned(),
15019                worktree_id,
15020                file,
15021            )
15022        });
15023
15024        let tags = mem::take(&mut runnable.tags);
15025        let language = runnable.language.clone();
15026        cx.spawn(async move |cx| {
15027            let mut templates_with_tags = Vec::new();
15028            if let Some(inventory) = inventory {
15029                for RunnableTag(tag) in tags {
15030                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15031                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15032                    }) else {
15033                        return templates_with_tags;
15034                    };
15035                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15036                        move |(_, template)| {
15037                            template.tags.iter().any(|source_tag| source_tag == &tag)
15038                        },
15039                    ));
15040                }
15041            }
15042            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15043
15044            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15045                // Strongest source wins; if we have worktree tag binding, prefer that to
15046                // global and language bindings;
15047                // if we have a global binding, prefer that to language binding.
15048                let first_mismatch = templates_with_tags
15049                    .iter()
15050                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15051                if let Some(index) = first_mismatch {
15052                    templates_with_tags.truncate(index);
15053                }
15054            }
15055
15056            templates_with_tags
15057        })
15058    }
15059
15060    pub fn move_to_enclosing_bracket(
15061        &mut self,
15062        _: &MoveToEnclosingBracket,
15063        window: &mut Window,
15064        cx: &mut Context<Self>,
15065    ) {
15066        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15067        self.change_selections(Default::default(), window, cx, |s| {
15068            s.move_offsets_with(|snapshot, selection| {
15069                let Some(enclosing_bracket_ranges) =
15070                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15071                else {
15072                    return;
15073                };
15074
15075                let mut best_length = usize::MAX;
15076                let mut best_inside = false;
15077                let mut best_in_bracket_range = false;
15078                let mut best_destination = None;
15079                for (open, close) in enclosing_bracket_ranges {
15080                    let close = close.to_inclusive();
15081                    let length = close.end() - open.start;
15082                    let inside = selection.start >= open.end && selection.end <= *close.start();
15083                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15084                        || close.contains(&selection.head());
15085
15086                    // If best is next to a bracket and current isn't, skip
15087                    if !in_bracket_range && best_in_bracket_range {
15088                        continue;
15089                    }
15090
15091                    // Prefer smaller lengths unless best is inside and current isn't
15092                    if length > best_length && (best_inside || !inside) {
15093                        continue;
15094                    }
15095
15096                    best_length = length;
15097                    best_inside = inside;
15098                    best_in_bracket_range = in_bracket_range;
15099                    best_destination = Some(
15100                        if close.contains(&selection.start) && close.contains(&selection.end) {
15101                            if inside { open.end } else { open.start }
15102                        } else if inside {
15103                            *close.start()
15104                        } else {
15105                            *close.end()
15106                        },
15107                    );
15108                }
15109
15110                if let Some(destination) = best_destination {
15111                    selection.collapse_to(destination, SelectionGoal::None);
15112                }
15113            })
15114        });
15115    }
15116
15117    pub fn undo_selection(
15118        &mut self,
15119        _: &UndoSelection,
15120        window: &mut Window,
15121        cx: &mut Context<Self>,
15122    ) {
15123        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15124        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15125            self.selection_history.mode = SelectionHistoryMode::Undoing;
15126            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15127                this.end_selection(window, cx);
15128                this.change_selections(
15129                    SelectionEffects::scroll(Autoscroll::newest()),
15130                    window,
15131                    cx,
15132                    |s| s.select_anchors(entry.selections.to_vec()),
15133                );
15134            });
15135            self.selection_history.mode = SelectionHistoryMode::Normal;
15136
15137            self.select_next_state = entry.select_next_state;
15138            self.select_prev_state = entry.select_prev_state;
15139            self.add_selections_state = entry.add_selections_state;
15140        }
15141    }
15142
15143    pub fn redo_selection(
15144        &mut self,
15145        _: &RedoSelection,
15146        window: &mut Window,
15147        cx: &mut Context<Self>,
15148    ) {
15149        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15150        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15151            self.selection_history.mode = SelectionHistoryMode::Redoing;
15152            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15153                this.end_selection(window, cx);
15154                this.change_selections(
15155                    SelectionEffects::scroll(Autoscroll::newest()),
15156                    window,
15157                    cx,
15158                    |s| s.select_anchors(entry.selections.to_vec()),
15159                );
15160            });
15161            self.selection_history.mode = SelectionHistoryMode::Normal;
15162
15163            self.select_next_state = entry.select_next_state;
15164            self.select_prev_state = entry.select_prev_state;
15165            self.add_selections_state = entry.add_selections_state;
15166        }
15167    }
15168
15169    pub fn expand_excerpts(
15170        &mut self,
15171        action: &ExpandExcerpts,
15172        _: &mut Window,
15173        cx: &mut Context<Self>,
15174    ) {
15175        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15176    }
15177
15178    pub fn expand_excerpts_down(
15179        &mut self,
15180        action: &ExpandExcerptsDown,
15181        _: &mut Window,
15182        cx: &mut Context<Self>,
15183    ) {
15184        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15185    }
15186
15187    pub fn expand_excerpts_up(
15188        &mut self,
15189        action: &ExpandExcerptsUp,
15190        _: &mut Window,
15191        cx: &mut Context<Self>,
15192    ) {
15193        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15194    }
15195
15196    pub fn expand_excerpts_for_direction(
15197        &mut self,
15198        lines: u32,
15199        direction: ExpandExcerptDirection,
15200
15201        cx: &mut Context<Self>,
15202    ) {
15203        let selections = self.selections.disjoint_anchors();
15204
15205        let lines = if lines == 0 {
15206            EditorSettings::get_global(cx).expand_excerpt_lines
15207        } else {
15208            lines
15209        };
15210
15211        self.buffer.update(cx, |buffer, cx| {
15212            let snapshot = buffer.snapshot(cx);
15213            let mut excerpt_ids = selections
15214                .iter()
15215                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15216                .collect::<Vec<_>>();
15217            excerpt_ids.sort();
15218            excerpt_ids.dedup();
15219            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15220        })
15221    }
15222
15223    pub fn expand_excerpt(
15224        &mut self,
15225        excerpt: ExcerptId,
15226        direction: ExpandExcerptDirection,
15227        window: &mut Window,
15228        cx: &mut Context<Self>,
15229    ) {
15230        let current_scroll_position = self.scroll_position(cx);
15231        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15232        let mut should_scroll_up = false;
15233
15234        if direction == ExpandExcerptDirection::Down {
15235            let multi_buffer = self.buffer.read(cx);
15236            let snapshot = multi_buffer.snapshot(cx);
15237            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
15238                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
15239                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
15240                        let buffer_snapshot = buffer.read(cx).snapshot();
15241                        let excerpt_end_row =
15242                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15243                        let last_row = buffer_snapshot.max_point().row;
15244                        let lines_below = last_row.saturating_sub(excerpt_end_row);
15245                        should_scroll_up = lines_below >= lines_to_expand;
15246                    }
15247                }
15248            }
15249        }
15250
15251        self.buffer.update(cx, |buffer, cx| {
15252            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15253        });
15254
15255        if should_scroll_up {
15256            let new_scroll_position =
15257                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15258            self.set_scroll_position(new_scroll_position, window, cx);
15259        }
15260    }
15261
15262    pub fn go_to_singleton_buffer_point(
15263        &mut self,
15264        point: Point,
15265        window: &mut Window,
15266        cx: &mut Context<Self>,
15267    ) {
15268        self.go_to_singleton_buffer_range(point..point, window, cx);
15269    }
15270
15271    pub fn go_to_singleton_buffer_range(
15272        &mut self,
15273        range: Range<Point>,
15274        window: &mut Window,
15275        cx: &mut Context<Self>,
15276    ) {
15277        let multibuffer = self.buffer().read(cx);
15278        let Some(buffer) = multibuffer.as_singleton() else {
15279            return;
15280        };
15281        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15282            return;
15283        };
15284        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15285            return;
15286        };
15287        self.change_selections(
15288            SelectionEffects::default().nav_history(true),
15289            window,
15290            cx,
15291            |s| s.select_anchor_ranges([start..end]),
15292        );
15293    }
15294
15295    pub fn go_to_diagnostic(
15296        &mut self,
15297        action: &GoToDiagnostic,
15298        window: &mut Window,
15299        cx: &mut Context<Self>,
15300    ) {
15301        if !self.diagnostics_enabled() {
15302            return;
15303        }
15304        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15305        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15306    }
15307
15308    pub fn go_to_prev_diagnostic(
15309        &mut self,
15310        action: &GoToPreviousDiagnostic,
15311        window: &mut Window,
15312        cx: &mut Context<Self>,
15313    ) {
15314        if !self.diagnostics_enabled() {
15315            return;
15316        }
15317        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15318        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15319    }
15320
15321    pub fn go_to_diagnostic_impl(
15322        &mut self,
15323        direction: Direction,
15324        severity: GoToDiagnosticSeverityFilter,
15325        window: &mut Window,
15326        cx: &mut Context<Self>,
15327    ) {
15328        let buffer = self.buffer.read(cx).snapshot(cx);
15329        let selection = self.selections.newest::<usize>(cx);
15330
15331        let mut active_group_id = None;
15332        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
15333            if active_group.active_range.start.to_offset(&buffer) == selection.start {
15334                active_group_id = Some(active_group.group_id);
15335            }
15336        }
15337
15338        fn filtered(
15339            snapshot: EditorSnapshot,
15340            severity: GoToDiagnosticSeverityFilter,
15341            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15342        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15343            diagnostics
15344                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15345                .filter(|entry| entry.range.start != entry.range.end)
15346                .filter(|entry| !entry.diagnostic.is_unnecessary)
15347                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15348        }
15349
15350        let snapshot = self.snapshot(window, cx);
15351        let before = filtered(
15352            snapshot.clone(),
15353            severity,
15354            buffer
15355                .diagnostics_in_range(0..selection.start)
15356                .filter(|entry| entry.range.start <= selection.start),
15357        );
15358        let after = filtered(
15359            snapshot,
15360            severity,
15361            buffer
15362                .diagnostics_in_range(selection.start..buffer.len())
15363                .filter(|entry| entry.range.start >= selection.start),
15364        );
15365
15366        let mut found: Option<DiagnosticEntry<usize>> = None;
15367        if direction == Direction::Prev {
15368            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15369            {
15370                for diagnostic in prev_diagnostics.into_iter().rev() {
15371                    if diagnostic.range.start != selection.start
15372                        || active_group_id
15373                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15374                    {
15375                        found = Some(diagnostic);
15376                        break 'outer;
15377                    }
15378                }
15379            }
15380        } else {
15381            for diagnostic in after.chain(before) {
15382                if diagnostic.range.start != selection.start
15383                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15384                {
15385                    found = Some(diagnostic);
15386                    break;
15387                }
15388            }
15389        }
15390        let Some(next_diagnostic) = found else {
15391            return;
15392        };
15393
15394        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
15395            return;
15396        };
15397        self.change_selections(Default::default(), window, cx, |s| {
15398            s.select_ranges(vec![
15399                next_diagnostic.range.start..next_diagnostic.range.start,
15400            ])
15401        });
15402        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15403        self.refresh_edit_prediction(false, true, window, cx);
15404    }
15405
15406    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15407        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15408        let snapshot = self.snapshot(window, cx);
15409        let selection = self.selections.newest::<Point>(cx);
15410        self.go_to_hunk_before_or_after_position(
15411            &snapshot,
15412            selection.head(),
15413            Direction::Next,
15414            window,
15415            cx,
15416        );
15417    }
15418
15419    pub fn go_to_hunk_before_or_after_position(
15420        &mut self,
15421        snapshot: &EditorSnapshot,
15422        position: Point,
15423        direction: Direction,
15424        window: &mut Window,
15425        cx: &mut Context<Editor>,
15426    ) {
15427        let row = if direction == Direction::Next {
15428            self.hunk_after_position(snapshot, position)
15429                .map(|hunk| hunk.row_range.start)
15430        } else {
15431            self.hunk_before_position(snapshot, position)
15432        };
15433
15434        if let Some(row) = row {
15435            let destination = Point::new(row.0, 0);
15436            let autoscroll = Autoscroll::center();
15437
15438            self.unfold_ranges(&[destination..destination], false, false, cx);
15439            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15440                s.select_ranges([destination..destination]);
15441            });
15442        }
15443    }
15444
15445    fn hunk_after_position(
15446        &mut self,
15447        snapshot: &EditorSnapshot,
15448        position: Point,
15449    ) -> Option<MultiBufferDiffHunk> {
15450        snapshot
15451            .buffer_snapshot
15452            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15453            .find(|hunk| hunk.row_range.start.0 > position.row)
15454            .or_else(|| {
15455                snapshot
15456                    .buffer_snapshot
15457                    .diff_hunks_in_range(Point::zero()..position)
15458                    .find(|hunk| hunk.row_range.end.0 < position.row)
15459            })
15460    }
15461
15462    fn go_to_prev_hunk(
15463        &mut self,
15464        _: &GoToPreviousHunk,
15465        window: &mut Window,
15466        cx: &mut Context<Self>,
15467    ) {
15468        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15469        let snapshot = self.snapshot(window, cx);
15470        let selection = self.selections.newest::<Point>(cx);
15471        self.go_to_hunk_before_or_after_position(
15472            &snapshot,
15473            selection.head(),
15474            Direction::Prev,
15475            window,
15476            cx,
15477        );
15478    }
15479
15480    fn hunk_before_position(
15481        &mut self,
15482        snapshot: &EditorSnapshot,
15483        position: Point,
15484    ) -> Option<MultiBufferRow> {
15485        snapshot
15486            .buffer_snapshot
15487            .diff_hunk_before(position)
15488            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15489    }
15490
15491    fn go_to_next_change(
15492        &mut self,
15493        _: &GoToNextChange,
15494        window: &mut Window,
15495        cx: &mut Context<Self>,
15496    ) {
15497        if let Some(selections) = self
15498            .change_list
15499            .next_change(1, Direction::Next)
15500            .map(|s| s.to_vec())
15501        {
15502            self.change_selections(Default::default(), window, cx, |s| {
15503                let map = s.display_map();
15504                s.select_display_ranges(selections.iter().map(|a| {
15505                    let point = a.to_display_point(&map);
15506                    point..point
15507                }))
15508            })
15509        }
15510    }
15511
15512    fn go_to_previous_change(
15513        &mut self,
15514        _: &GoToPreviousChange,
15515        window: &mut Window,
15516        cx: &mut Context<Self>,
15517    ) {
15518        if let Some(selections) = self
15519            .change_list
15520            .next_change(1, Direction::Prev)
15521            .map(|s| s.to_vec())
15522        {
15523            self.change_selections(Default::default(), window, cx, |s| {
15524                let map = s.display_map();
15525                s.select_display_ranges(selections.iter().map(|a| {
15526                    let point = a.to_display_point(&map);
15527                    point..point
15528                }))
15529            })
15530        }
15531    }
15532
15533    fn go_to_line<T: 'static>(
15534        &mut self,
15535        position: Anchor,
15536        highlight_color: Option<Hsla>,
15537        window: &mut Window,
15538        cx: &mut Context<Self>,
15539    ) {
15540        let snapshot = self.snapshot(window, cx).display_snapshot;
15541        let position = position.to_point(&snapshot.buffer_snapshot);
15542        let start = snapshot
15543            .buffer_snapshot
15544            .clip_point(Point::new(position.row, 0), Bias::Left);
15545        let end = start + Point::new(1, 0);
15546        let start = snapshot.buffer_snapshot.anchor_before(start);
15547        let end = snapshot.buffer_snapshot.anchor_before(end);
15548
15549        self.highlight_rows::<T>(
15550            start..end,
15551            highlight_color
15552                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15553            Default::default(),
15554            cx,
15555        );
15556
15557        if self.buffer.read(cx).is_singleton() {
15558            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15559        }
15560    }
15561
15562    pub fn go_to_definition(
15563        &mut self,
15564        _: &GoToDefinition,
15565        window: &mut Window,
15566        cx: &mut Context<Self>,
15567    ) -> Task<Result<Navigated>> {
15568        let definition =
15569            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15570        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15571        cx.spawn_in(window, async move |editor, cx| {
15572            if definition.await? == Navigated::Yes {
15573                return Ok(Navigated::Yes);
15574            }
15575            match fallback_strategy {
15576                GoToDefinitionFallback::None => Ok(Navigated::No),
15577                GoToDefinitionFallback::FindAllReferences => {
15578                    match editor.update_in(cx, |editor, window, cx| {
15579                        editor.find_all_references(&FindAllReferences, window, cx)
15580                    })? {
15581                        Some(references) => references.await,
15582                        None => Ok(Navigated::No),
15583                    }
15584                }
15585            }
15586        })
15587    }
15588
15589    pub fn go_to_declaration(
15590        &mut self,
15591        _: &GoToDeclaration,
15592        window: &mut Window,
15593        cx: &mut Context<Self>,
15594    ) -> Task<Result<Navigated>> {
15595        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15596    }
15597
15598    pub fn go_to_declaration_split(
15599        &mut self,
15600        _: &GoToDeclaration,
15601        window: &mut Window,
15602        cx: &mut Context<Self>,
15603    ) -> Task<Result<Navigated>> {
15604        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15605    }
15606
15607    pub fn go_to_implementation(
15608        &mut self,
15609        _: &GoToImplementation,
15610        window: &mut Window,
15611        cx: &mut Context<Self>,
15612    ) -> Task<Result<Navigated>> {
15613        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15614    }
15615
15616    pub fn go_to_implementation_split(
15617        &mut self,
15618        _: &GoToImplementationSplit,
15619        window: &mut Window,
15620        cx: &mut Context<Self>,
15621    ) -> Task<Result<Navigated>> {
15622        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15623    }
15624
15625    pub fn go_to_type_definition(
15626        &mut self,
15627        _: &GoToTypeDefinition,
15628        window: &mut Window,
15629        cx: &mut Context<Self>,
15630    ) -> Task<Result<Navigated>> {
15631        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15632    }
15633
15634    pub fn go_to_definition_split(
15635        &mut self,
15636        _: &GoToDefinitionSplit,
15637        window: &mut Window,
15638        cx: &mut Context<Self>,
15639    ) -> Task<Result<Navigated>> {
15640        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15641    }
15642
15643    pub fn go_to_type_definition_split(
15644        &mut self,
15645        _: &GoToTypeDefinitionSplit,
15646        window: &mut Window,
15647        cx: &mut Context<Self>,
15648    ) -> Task<Result<Navigated>> {
15649        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15650    }
15651
15652    fn go_to_definition_of_kind(
15653        &mut self,
15654        kind: GotoDefinitionKind,
15655        split: bool,
15656        window: &mut Window,
15657        cx: &mut Context<Self>,
15658    ) -> Task<Result<Navigated>> {
15659        let Some(provider) = self.semantics_provider.clone() else {
15660            return Task::ready(Ok(Navigated::No));
15661        };
15662        let head = self.selections.newest::<usize>(cx).head();
15663        let buffer = self.buffer.read(cx);
15664        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
15665            text_anchor
15666        } else {
15667            return Task::ready(Ok(Navigated::No));
15668        };
15669
15670        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15671            return Task::ready(Ok(Navigated::No));
15672        };
15673
15674        cx.spawn_in(window, async move |editor, cx| {
15675            let definitions = definitions.await?;
15676            let navigated = editor
15677                .update_in(cx, |editor, window, cx| {
15678                    editor.navigate_to_hover_links(
15679                        Some(kind),
15680                        definitions
15681                            .into_iter()
15682                            .filter(|location| {
15683                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15684                            })
15685                            .map(HoverLink::Text)
15686                            .collect::<Vec<_>>(),
15687                        split,
15688                        window,
15689                        cx,
15690                    )
15691                })?
15692                .await?;
15693            anyhow::Ok(navigated)
15694        })
15695    }
15696
15697    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15698        let selection = self.selections.newest_anchor();
15699        let head = selection.head();
15700        let tail = selection.tail();
15701
15702        let Some((buffer, start_position)) =
15703            self.buffer.read(cx).text_anchor_for_position(head, cx)
15704        else {
15705            return;
15706        };
15707
15708        let end_position = if head != tail {
15709            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15710                return;
15711            };
15712            Some(pos)
15713        } else {
15714            None
15715        };
15716
15717        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15718            let url = if let Some(end_pos) = end_position {
15719                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15720            } else {
15721                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15722            };
15723
15724            if let Some(url) = url {
15725                editor.update(cx, |_, cx| {
15726                    cx.open_url(&url);
15727                })
15728            } else {
15729                Ok(())
15730            }
15731        });
15732
15733        url_finder.detach();
15734    }
15735
15736    pub fn open_selected_filename(
15737        &mut self,
15738        _: &OpenSelectedFilename,
15739        window: &mut Window,
15740        cx: &mut Context<Self>,
15741    ) {
15742        let Some(workspace) = self.workspace() else {
15743            return;
15744        };
15745
15746        let position = self.selections.newest_anchor().head();
15747
15748        let Some((buffer, buffer_position)) =
15749            self.buffer.read(cx).text_anchor_for_position(position, cx)
15750        else {
15751            return;
15752        };
15753
15754        let project = self.project.clone();
15755
15756        cx.spawn_in(window, async move |_, cx| {
15757            let result = find_file(&buffer, project, buffer_position, cx).await;
15758
15759            if let Some((_, path)) = result {
15760                workspace
15761                    .update_in(cx, |workspace, window, cx| {
15762                        workspace.open_resolved_path(path, window, cx)
15763                    })?
15764                    .await?;
15765            }
15766            anyhow::Ok(())
15767        })
15768        .detach();
15769    }
15770
15771    pub(crate) fn navigate_to_hover_links(
15772        &mut self,
15773        kind: Option<GotoDefinitionKind>,
15774        mut definitions: Vec<HoverLink>,
15775        split: bool,
15776        window: &mut Window,
15777        cx: &mut Context<Editor>,
15778    ) -> Task<Result<Navigated>> {
15779        // If there is one definition, just open it directly
15780        if definitions.len() == 1 {
15781            let definition = definitions.pop().unwrap();
15782
15783            enum TargetTaskResult {
15784                Location(Option<Location>),
15785                AlreadyNavigated,
15786            }
15787
15788            let target_task = match definition {
15789                HoverLink::Text(link) => {
15790                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
15791                }
15792                HoverLink::InlayHint(lsp_location, server_id) => {
15793                    let computation =
15794                        self.compute_target_location(lsp_location, server_id, window, cx);
15795                    cx.background_spawn(async move {
15796                        let location = computation.await?;
15797                        Ok(TargetTaskResult::Location(location))
15798                    })
15799                }
15800                HoverLink::Url(url) => {
15801                    cx.open_url(&url);
15802                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15803                }
15804                HoverLink::File(path) => {
15805                    if let Some(workspace) = self.workspace() {
15806                        cx.spawn_in(window, async move |_, cx| {
15807                            workspace
15808                                .update_in(cx, |workspace, window, cx| {
15809                                    workspace.open_resolved_path(path, window, cx)
15810                                })?
15811                                .await
15812                                .map(|_| TargetTaskResult::AlreadyNavigated)
15813                        })
15814                    } else {
15815                        Task::ready(Ok(TargetTaskResult::Location(None)))
15816                    }
15817                }
15818            };
15819            cx.spawn_in(window, async move |editor, cx| {
15820                let target = match target_task.await.context("target resolution task")? {
15821                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15822                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15823                    TargetTaskResult::Location(Some(target)) => target,
15824                };
15825
15826                editor.update_in(cx, |editor, window, cx| {
15827                    let Some(workspace) = editor.workspace() else {
15828                        return Navigated::No;
15829                    };
15830                    let pane = workspace.read(cx).active_pane().clone();
15831
15832                    let range = target.range.to_point(target.buffer.read(cx));
15833                    let range = editor.range_for_match(&range);
15834                    let range = collapse_multiline_range(range);
15835
15836                    if !split
15837                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15838                    {
15839                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15840                    } else {
15841                        window.defer(cx, move |window, cx| {
15842                            let target_editor: Entity<Self> =
15843                                workspace.update(cx, |workspace, cx| {
15844                                    let pane = if split {
15845                                        workspace.adjacent_pane(window, cx)
15846                                    } else {
15847                                        workspace.active_pane().clone()
15848                                    };
15849
15850                                    workspace.open_project_item(
15851                                        pane,
15852                                        target.buffer.clone(),
15853                                        true,
15854                                        true,
15855                                        window,
15856                                        cx,
15857                                    )
15858                                });
15859                            target_editor.update(cx, |target_editor, cx| {
15860                                // When selecting a definition in a different buffer, disable the nav history
15861                                // to avoid creating a history entry at the previous cursor location.
15862                                pane.update(cx, |pane, _| pane.disable_history());
15863                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15864                                pane.update(cx, |pane, _| pane.enable_history());
15865                            });
15866                        });
15867                    }
15868                    Navigated::Yes
15869                })
15870            })
15871        } else if !definitions.is_empty() {
15872            cx.spawn_in(window, async move |editor, cx| {
15873                let (title, location_tasks, workspace) = editor
15874                    .update_in(cx, |editor, window, cx| {
15875                        let tab_kind = match kind {
15876                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15877                            _ => "Definitions",
15878                        };
15879                        let title = definitions
15880                            .iter()
15881                            .find_map(|definition| match definition {
15882                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15883                                    let buffer = origin.buffer.read(cx);
15884                                    format!(
15885                                        "{} for {}",
15886                                        tab_kind,
15887                                        buffer
15888                                            .text_for_range(origin.range.clone())
15889                                            .collect::<String>()
15890                                    )
15891                                }),
15892                                HoverLink::InlayHint(_, _) => None,
15893                                HoverLink::Url(_) => None,
15894                                HoverLink::File(_) => None,
15895                            })
15896                            .unwrap_or(tab_kind.to_string());
15897                        let location_tasks = definitions
15898                            .into_iter()
15899                            .map(|definition| match definition {
15900                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15901                                HoverLink::InlayHint(lsp_location, server_id) => editor
15902                                    .compute_target_location(lsp_location, server_id, window, cx),
15903                                HoverLink::Url(_) => Task::ready(Ok(None)),
15904                                HoverLink::File(_) => Task::ready(Ok(None)),
15905                            })
15906                            .collect::<Vec<_>>();
15907                        (title, location_tasks, editor.workspace().clone())
15908                    })
15909                    .context("location tasks preparation")?;
15910
15911                let locations: Vec<Location> = future::join_all(location_tasks)
15912                    .await
15913                    .into_iter()
15914                    .filter_map(|location| location.transpose())
15915                    .collect::<Result<_>>()
15916                    .context("location tasks")?;
15917
15918                if locations.is_empty() {
15919                    return Ok(Navigated::No);
15920                }
15921
15922                let Some(workspace) = workspace else {
15923                    return Ok(Navigated::No);
15924                };
15925
15926                let opened = workspace
15927                    .update_in(cx, |workspace, window, cx| {
15928                        Self::open_locations_in_multibuffer(
15929                            workspace,
15930                            locations,
15931                            title,
15932                            split,
15933                            MultibufferSelectionMode::First,
15934                            window,
15935                            cx,
15936                        )
15937                    })
15938                    .ok();
15939
15940                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15941            })
15942        } else {
15943            Task::ready(Ok(Navigated::No))
15944        }
15945    }
15946
15947    fn compute_target_location(
15948        &self,
15949        lsp_location: lsp::Location,
15950        server_id: LanguageServerId,
15951        window: &mut Window,
15952        cx: &mut Context<Self>,
15953    ) -> Task<anyhow::Result<Option<Location>>> {
15954        let Some(project) = self.project.clone() else {
15955            return Task::ready(Ok(None));
15956        };
15957
15958        cx.spawn_in(window, async move |editor, cx| {
15959            let location_task = editor.update(cx, |_, cx| {
15960                project.update(cx, |project, cx| {
15961                    let language_server_name = project
15962                        .language_server_statuses(cx)
15963                        .find(|(id, _)| server_id == *id)
15964                        .map(|(_, status)| status.name.clone());
15965                    language_server_name.map(|language_server_name| {
15966                        project.open_local_buffer_via_lsp(
15967                            lsp_location.uri.clone(),
15968                            server_id,
15969                            language_server_name,
15970                            cx,
15971                        )
15972                    })
15973                })
15974            })?;
15975            let location = match location_task {
15976                Some(task) => Some({
15977                    let target_buffer_handle = task.await.context("open local buffer")?;
15978                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15979                        let target_start = target_buffer
15980                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15981                        let target_end = target_buffer
15982                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15983                        target_buffer.anchor_after(target_start)
15984                            ..target_buffer.anchor_before(target_end)
15985                    })?;
15986                    Location {
15987                        buffer: target_buffer_handle,
15988                        range,
15989                    }
15990                }),
15991                None => None,
15992            };
15993            Ok(location)
15994        })
15995    }
15996
15997    pub fn find_all_references(
15998        &mut self,
15999        _: &FindAllReferences,
16000        window: &mut Window,
16001        cx: &mut Context<Self>,
16002    ) -> Option<Task<Result<Navigated>>> {
16003        let selection = self.selections.newest::<usize>(cx);
16004        let multi_buffer = self.buffer.read(cx);
16005        let head = selection.head();
16006
16007        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16008        let head_anchor = multi_buffer_snapshot.anchor_at(
16009            head,
16010            if head < selection.tail() {
16011                Bias::Right
16012            } else {
16013                Bias::Left
16014            },
16015        );
16016
16017        match self
16018            .find_all_references_task_sources
16019            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16020        {
16021            Ok(_) => {
16022                log::info!(
16023                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16024                );
16025                return None;
16026            }
16027            Err(i) => {
16028                self.find_all_references_task_sources.insert(i, head_anchor);
16029            }
16030        }
16031
16032        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16033        let workspace = self.workspace()?;
16034        let project = workspace.read(cx).project().clone();
16035        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16036        Some(cx.spawn_in(window, async move |editor, cx| {
16037            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16038                if let Ok(i) = editor
16039                    .find_all_references_task_sources
16040                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16041                {
16042                    editor.find_all_references_task_sources.remove(i);
16043                }
16044            });
16045
16046            let locations = references.await?;
16047            if locations.is_empty() {
16048                return anyhow::Ok(Navigated::No);
16049            }
16050
16051            workspace.update_in(cx, |workspace, window, cx| {
16052                let title = locations
16053                    .first()
16054                    .as_ref()
16055                    .map(|location| {
16056                        let buffer = location.buffer.read(cx);
16057                        format!(
16058                            "References to `{}`",
16059                            buffer
16060                                .text_for_range(location.range.clone())
16061                                .collect::<String>()
16062                        )
16063                    })
16064                    .unwrap();
16065                Self::open_locations_in_multibuffer(
16066                    workspace,
16067                    locations,
16068                    title,
16069                    false,
16070                    MultibufferSelectionMode::First,
16071                    window,
16072                    cx,
16073                );
16074                Navigated::Yes
16075            })
16076        }))
16077    }
16078
16079    /// Opens a multibuffer with the given project locations in it
16080    pub fn open_locations_in_multibuffer(
16081        workspace: &mut Workspace,
16082        mut locations: Vec<Location>,
16083        title: String,
16084        split: bool,
16085        multibuffer_selection_mode: MultibufferSelectionMode,
16086        window: &mut Window,
16087        cx: &mut Context<Workspace>,
16088    ) {
16089        if locations.is_empty() {
16090            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16091            return;
16092        }
16093
16094        // If there are multiple definitions, open them in a multibuffer
16095        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16096        let mut locations = locations.into_iter().peekable();
16097        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16098        let capability = workspace.project().read(cx).capability();
16099
16100        let excerpt_buffer = cx.new(|cx| {
16101            let mut multibuffer = MultiBuffer::new(capability);
16102            while let Some(location) = locations.next() {
16103                let buffer = location.buffer.read(cx);
16104                let mut ranges_for_buffer = Vec::new();
16105                let range = location.range.to_point(buffer);
16106                ranges_for_buffer.push(range.clone());
16107
16108                while let Some(next_location) = locations.peek() {
16109                    if next_location.buffer == location.buffer {
16110                        ranges_for_buffer.push(next_location.range.to_point(buffer));
16111                        locations.next();
16112                    } else {
16113                        break;
16114                    }
16115                }
16116
16117                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16118                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16119                    PathKey::for_buffer(&location.buffer, cx),
16120                    location.buffer.clone(),
16121                    ranges_for_buffer,
16122                    DEFAULT_MULTIBUFFER_CONTEXT,
16123                    cx,
16124                );
16125                ranges.extend(new_ranges)
16126            }
16127
16128            multibuffer.with_title(title)
16129        });
16130
16131        let editor = cx.new(|cx| {
16132            Editor::for_multibuffer(
16133                excerpt_buffer,
16134                Some(workspace.project().clone()),
16135                window,
16136                cx,
16137            )
16138        });
16139        editor.update(cx, |editor, cx| {
16140            match multibuffer_selection_mode {
16141                MultibufferSelectionMode::First => {
16142                    if let Some(first_range) = ranges.first() {
16143                        editor.change_selections(
16144                            SelectionEffects::no_scroll(),
16145                            window,
16146                            cx,
16147                            |selections| {
16148                                selections.clear_disjoint();
16149                                selections
16150                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16151                            },
16152                        );
16153                    }
16154                    editor.highlight_background::<Self>(
16155                        &ranges,
16156                        |theme| theme.colors().editor_highlighted_line_background,
16157                        cx,
16158                    );
16159                }
16160                MultibufferSelectionMode::All => {
16161                    editor.change_selections(
16162                        SelectionEffects::no_scroll(),
16163                        window,
16164                        cx,
16165                        |selections| {
16166                            selections.clear_disjoint();
16167                            selections.select_anchor_ranges(ranges);
16168                        },
16169                    );
16170                }
16171            }
16172            editor.register_buffers_with_language_servers(cx);
16173        });
16174
16175        let item = Box::new(editor);
16176        let item_id = item.item_id();
16177
16178        if split {
16179            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
16180        } else {
16181            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16182                let (preview_item_id, preview_item_idx) =
16183                    workspace.active_pane().read_with(cx, |pane, _| {
16184                        (pane.preview_item_id(), pane.preview_item_idx())
16185                    });
16186
16187                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
16188
16189                if let Some(preview_item_id) = preview_item_id {
16190                    workspace.active_pane().update(cx, |pane, cx| {
16191                        pane.remove_item(preview_item_id, false, false, window, cx);
16192                    });
16193                }
16194            } else {
16195                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
16196            }
16197        }
16198        workspace.active_pane().update(cx, |pane, cx| {
16199            pane.set_preview_item_id(Some(item_id), cx);
16200        });
16201    }
16202
16203    pub fn rename(
16204        &mut self,
16205        _: &Rename,
16206        window: &mut Window,
16207        cx: &mut Context<Self>,
16208    ) -> Option<Task<Result<()>>> {
16209        use language::ToOffset as _;
16210
16211        let provider = self.semantics_provider.clone()?;
16212        let selection = self.selections.newest_anchor().clone();
16213        let (cursor_buffer, cursor_buffer_position) = self
16214            .buffer
16215            .read(cx)
16216            .text_anchor_for_position(selection.head(), cx)?;
16217        let (tail_buffer, cursor_buffer_position_end) = self
16218            .buffer
16219            .read(cx)
16220            .text_anchor_for_position(selection.tail(), cx)?;
16221        if tail_buffer != cursor_buffer {
16222            return None;
16223        }
16224
16225        let snapshot = cursor_buffer.read(cx).snapshot();
16226        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16227        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16228        let prepare_rename = provider
16229            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16230            .unwrap_or_else(|| Task::ready(Ok(None)));
16231        drop(snapshot);
16232
16233        Some(cx.spawn_in(window, async move |this, cx| {
16234            let rename_range = if let Some(range) = prepare_rename.await? {
16235                Some(range)
16236            } else {
16237                this.update(cx, |this, cx| {
16238                    let buffer = this.buffer.read(cx).snapshot(cx);
16239                    let mut buffer_highlights = this
16240                        .document_highlights_for_position(selection.head(), &buffer)
16241                        .filter(|highlight| {
16242                            highlight.start.excerpt_id == selection.head().excerpt_id
16243                                && highlight.end.excerpt_id == selection.head().excerpt_id
16244                        });
16245                    buffer_highlights
16246                        .next()
16247                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16248                })?
16249            };
16250            if let Some(rename_range) = rename_range {
16251                this.update_in(cx, |this, window, cx| {
16252                    let snapshot = cursor_buffer.read(cx).snapshot();
16253                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16254                    let cursor_offset_in_rename_range =
16255                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16256                    let cursor_offset_in_rename_range_end =
16257                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16258
16259                    this.take_rename(false, window, cx);
16260                    let buffer = this.buffer.read(cx).read(cx);
16261                    let cursor_offset = selection.head().to_offset(&buffer);
16262                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16263                    let rename_end = rename_start + rename_buffer_range.len();
16264                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16265                    let mut old_highlight_id = None;
16266                    let old_name: Arc<str> = buffer
16267                        .chunks(rename_start..rename_end, true)
16268                        .map(|chunk| {
16269                            if old_highlight_id.is_none() {
16270                                old_highlight_id = chunk.syntax_highlight_id;
16271                            }
16272                            chunk.text
16273                        })
16274                        .collect::<String>()
16275                        .into();
16276
16277                    drop(buffer);
16278
16279                    // Position the selection in the rename editor so that it matches the current selection.
16280                    this.show_local_selections = false;
16281                    let rename_editor = cx.new(|cx| {
16282                        let mut editor = Editor::single_line(window, cx);
16283                        editor.buffer.update(cx, |buffer, cx| {
16284                            buffer.edit([(0..0, old_name.clone())], None, cx)
16285                        });
16286                        let rename_selection_range = match cursor_offset_in_rename_range
16287                            .cmp(&cursor_offset_in_rename_range_end)
16288                        {
16289                            Ordering::Equal => {
16290                                editor.select_all(&SelectAll, window, cx);
16291                                return editor;
16292                            }
16293                            Ordering::Less => {
16294                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16295                            }
16296                            Ordering::Greater => {
16297                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16298                            }
16299                        };
16300                        if rename_selection_range.end > old_name.len() {
16301                            editor.select_all(&SelectAll, window, cx);
16302                        } else {
16303                            editor.change_selections(Default::default(), window, cx, |s| {
16304                                s.select_ranges([rename_selection_range]);
16305                            });
16306                        }
16307                        editor
16308                    });
16309                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16310                        if e == &EditorEvent::Focused {
16311                            cx.emit(EditorEvent::FocusedIn)
16312                        }
16313                    })
16314                    .detach();
16315
16316                    let write_highlights =
16317                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16318                    let read_highlights =
16319                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16320                    let ranges = write_highlights
16321                        .iter()
16322                        .flat_map(|(_, ranges)| ranges.iter())
16323                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16324                        .cloned()
16325                        .collect();
16326
16327                    this.highlight_text::<Rename>(
16328                        ranges,
16329                        HighlightStyle {
16330                            fade_out: Some(0.6),
16331                            ..Default::default()
16332                        },
16333                        cx,
16334                    );
16335                    let rename_focus_handle = rename_editor.focus_handle(cx);
16336                    window.focus(&rename_focus_handle);
16337                    let block_id = this.insert_blocks(
16338                        [BlockProperties {
16339                            style: BlockStyle::Flex,
16340                            placement: BlockPlacement::Below(range.start),
16341                            height: Some(1),
16342                            render: Arc::new({
16343                                let rename_editor = rename_editor.clone();
16344                                move |cx: &mut BlockContext| {
16345                                    let mut text_style = cx.editor_style.text.clone();
16346                                    if let Some(highlight_style) = old_highlight_id
16347                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16348                                    {
16349                                        text_style = text_style.highlight(highlight_style);
16350                                    }
16351                                    div()
16352                                        .block_mouse_except_scroll()
16353                                        .pl(cx.anchor_x)
16354                                        .child(EditorElement::new(
16355                                            &rename_editor,
16356                                            EditorStyle {
16357                                                background: cx.theme().system().transparent,
16358                                                local_player: cx.editor_style.local_player,
16359                                                text: text_style,
16360                                                scrollbar_width: cx.editor_style.scrollbar_width,
16361                                                syntax: cx.editor_style.syntax.clone(),
16362                                                status: cx.editor_style.status.clone(),
16363                                                inlay_hints_style: HighlightStyle {
16364                                                    font_weight: Some(FontWeight::BOLD),
16365                                                    ..make_inlay_hints_style(cx.app)
16366                                                },
16367                                                edit_prediction_styles: make_suggestion_styles(
16368                                                    cx.app,
16369                                                ),
16370                                                ..EditorStyle::default()
16371                                            },
16372                                        ))
16373                                        .into_any_element()
16374                                }
16375                            }),
16376                            priority: 0,
16377                        }],
16378                        Some(Autoscroll::fit()),
16379                        cx,
16380                    )[0];
16381                    this.pending_rename = Some(RenameState {
16382                        range,
16383                        old_name,
16384                        editor: rename_editor,
16385                        block_id,
16386                    });
16387                })?;
16388            }
16389
16390            Ok(())
16391        }))
16392    }
16393
16394    pub fn confirm_rename(
16395        &mut self,
16396        _: &ConfirmRename,
16397        window: &mut Window,
16398        cx: &mut Context<Self>,
16399    ) -> Option<Task<Result<()>>> {
16400        let rename = self.take_rename(false, window, cx)?;
16401        let workspace = self.workspace()?.downgrade();
16402        let (buffer, start) = self
16403            .buffer
16404            .read(cx)
16405            .text_anchor_for_position(rename.range.start, cx)?;
16406        let (end_buffer, _) = self
16407            .buffer
16408            .read(cx)
16409            .text_anchor_for_position(rename.range.end, cx)?;
16410        if buffer != end_buffer {
16411            return None;
16412        }
16413
16414        let old_name = rename.old_name;
16415        let new_name = rename.editor.read(cx).text(cx);
16416
16417        let rename = self.semantics_provider.as_ref()?.perform_rename(
16418            &buffer,
16419            start,
16420            new_name.clone(),
16421            cx,
16422        )?;
16423
16424        Some(cx.spawn_in(window, async move |editor, cx| {
16425            let project_transaction = rename.await?;
16426            Self::open_project_transaction(
16427                &editor,
16428                workspace,
16429                project_transaction,
16430                format!("Rename: {}{}", old_name, new_name),
16431                cx,
16432            )
16433            .await?;
16434
16435            editor.update(cx, |editor, cx| {
16436                editor.refresh_document_highlights(cx);
16437            })?;
16438            Ok(())
16439        }))
16440    }
16441
16442    fn take_rename(
16443        &mut self,
16444        moving_cursor: bool,
16445        window: &mut Window,
16446        cx: &mut Context<Self>,
16447    ) -> Option<RenameState> {
16448        let rename = self.pending_rename.take()?;
16449        if rename.editor.focus_handle(cx).is_focused(window) {
16450            window.focus(&self.focus_handle);
16451        }
16452
16453        self.remove_blocks(
16454            [rename.block_id].into_iter().collect(),
16455            Some(Autoscroll::fit()),
16456            cx,
16457        );
16458        self.clear_highlights::<Rename>(cx);
16459        self.show_local_selections = true;
16460
16461        if moving_cursor {
16462            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16463                editor.selections.newest::<usize>(cx).head()
16464            });
16465
16466            // Update the selection to match the position of the selection inside
16467            // the rename editor.
16468            let snapshot = self.buffer.read(cx).read(cx);
16469            let rename_range = rename.range.to_offset(&snapshot);
16470            let cursor_in_editor = snapshot
16471                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16472                .min(rename_range.end);
16473            drop(snapshot);
16474
16475            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16476                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16477            });
16478        } else {
16479            self.refresh_document_highlights(cx);
16480        }
16481
16482        Some(rename)
16483    }
16484
16485    pub fn pending_rename(&self) -> Option<&RenameState> {
16486        self.pending_rename.as_ref()
16487    }
16488
16489    fn format(
16490        &mut self,
16491        _: &Format,
16492        window: &mut Window,
16493        cx: &mut Context<Self>,
16494    ) -> Option<Task<Result<()>>> {
16495        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16496
16497        let project = match &self.project {
16498            Some(project) => project.clone(),
16499            None => return None,
16500        };
16501
16502        Some(self.perform_format(
16503            project,
16504            FormatTrigger::Manual,
16505            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16506            window,
16507            cx,
16508        ))
16509    }
16510
16511    fn format_selections(
16512        &mut self,
16513        _: &FormatSelections,
16514        window: &mut Window,
16515        cx: &mut Context<Self>,
16516    ) -> Option<Task<Result<()>>> {
16517        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16518
16519        let project = match &self.project {
16520            Some(project) => project.clone(),
16521            None => return None,
16522        };
16523
16524        let ranges = self
16525            .selections
16526            .all_adjusted(cx)
16527            .into_iter()
16528            .map(|selection| selection.range())
16529            .collect_vec();
16530
16531        Some(self.perform_format(
16532            project,
16533            FormatTrigger::Manual,
16534            FormatTarget::Ranges(ranges),
16535            window,
16536            cx,
16537        ))
16538    }
16539
16540    fn perform_format(
16541        &mut self,
16542        project: Entity<Project>,
16543        trigger: FormatTrigger,
16544        target: FormatTarget,
16545        window: &mut Window,
16546        cx: &mut Context<Self>,
16547    ) -> Task<Result<()>> {
16548        let buffer = self.buffer.clone();
16549        let (buffers, target) = match target {
16550            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16551            FormatTarget::Ranges(selection_ranges) => {
16552                let multi_buffer = buffer.read(cx);
16553                let snapshot = multi_buffer.read(cx);
16554                let mut buffers = HashSet::default();
16555                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16556                    BTreeMap::new();
16557                for selection_range in selection_ranges {
16558                    for (buffer, buffer_range, _) in
16559                        snapshot.range_to_buffer_ranges(selection_range)
16560                    {
16561                        let buffer_id = buffer.remote_id();
16562                        let start = buffer.anchor_before(buffer_range.start);
16563                        let end = buffer.anchor_after(buffer_range.end);
16564                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16565                        buffer_id_to_ranges
16566                            .entry(buffer_id)
16567                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16568                            .or_insert_with(|| vec![start..end]);
16569                    }
16570                }
16571                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16572            }
16573        };
16574
16575        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16576        let selections_prev = transaction_id_prev
16577            .and_then(|transaction_id_prev| {
16578                // default to selections as they were after the last edit, if we have them,
16579                // instead of how they are now.
16580                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16581                // will take you back to where you made the last edit, instead of staying where you scrolled
16582                self.selection_history
16583                    .transaction(transaction_id_prev)
16584                    .map(|t| t.0.clone())
16585            })
16586            .unwrap_or_else(|| {
16587                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
16588                self.selections.disjoint_anchors()
16589            });
16590
16591        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16592        let format = project.update(cx, |project, cx| {
16593            project.format(buffers, target, true, trigger, cx)
16594        });
16595
16596        cx.spawn_in(window, async move |editor, cx| {
16597            let transaction = futures::select_biased! {
16598                transaction = format.log_err().fuse() => transaction,
16599                () = timeout => {
16600                    log::warn!("timed out waiting for formatting");
16601                    None
16602                }
16603            };
16604
16605            buffer
16606                .update(cx, |buffer, cx| {
16607                    if let Some(transaction) = transaction {
16608                        if !buffer.is_singleton() {
16609                            buffer.push_transaction(&transaction.0, cx);
16610                        }
16611                    }
16612                    cx.notify();
16613                })
16614                .ok();
16615
16616            if let Some(transaction_id_now) =
16617                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16618            {
16619                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16620                if has_new_transaction {
16621                    _ = editor.update(cx, |editor, _| {
16622                        editor
16623                            .selection_history
16624                            .insert_transaction(transaction_id_now, selections_prev);
16625                    });
16626                }
16627            }
16628
16629            Ok(())
16630        })
16631    }
16632
16633    fn organize_imports(
16634        &mut self,
16635        _: &OrganizeImports,
16636        window: &mut Window,
16637        cx: &mut Context<Self>,
16638    ) -> Option<Task<Result<()>>> {
16639        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16640        let project = match &self.project {
16641            Some(project) => project.clone(),
16642            None => return None,
16643        };
16644        Some(self.perform_code_action_kind(
16645            project,
16646            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16647            window,
16648            cx,
16649        ))
16650    }
16651
16652    fn perform_code_action_kind(
16653        &mut self,
16654        project: Entity<Project>,
16655        kind: CodeActionKind,
16656        window: &mut Window,
16657        cx: &mut Context<Self>,
16658    ) -> Task<Result<()>> {
16659        let buffer = self.buffer.clone();
16660        let buffers = buffer.read(cx).all_buffers();
16661        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16662        let apply_action = project.update(cx, |project, cx| {
16663            project.apply_code_action_kind(buffers, kind, true, cx)
16664        });
16665        cx.spawn_in(window, async move |_, cx| {
16666            let transaction = futures::select_biased! {
16667                () = timeout => {
16668                    log::warn!("timed out waiting for executing code action");
16669                    None
16670                }
16671                transaction = apply_action.log_err().fuse() => transaction,
16672            };
16673            buffer
16674                .update(cx, |buffer, cx| {
16675                    // check if we need this
16676                    if let Some(transaction) = transaction {
16677                        if !buffer.is_singleton() {
16678                            buffer.push_transaction(&transaction.0, cx);
16679                        }
16680                    }
16681                    cx.notify();
16682                })
16683                .ok();
16684            Ok(())
16685        })
16686    }
16687
16688    pub fn restart_language_server(
16689        &mut self,
16690        _: &RestartLanguageServer,
16691        _: &mut Window,
16692        cx: &mut Context<Self>,
16693    ) {
16694        if let Some(project) = self.project.clone() {
16695            self.buffer.update(cx, |multi_buffer, cx| {
16696                project.update(cx, |project, cx| {
16697                    project.restart_language_servers_for_buffers(
16698                        multi_buffer.all_buffers().into_iter().collect(),
16699                        HashSet::default(),
16700                        cx,
16701                    );
16702                });
16703            })
16704        }
16705    }
16706
16707    pub fn stop_language_server(
16708        &mut self,
16709        _: &StopLanguageServer,
16710        _: &mut Window,
16711        cx: &mut Context<Self>,
16712    ) {
16713        if let Some(project) = self.project.clone() {
16714            self.buffer.update(cx, |multi_buffer, cx| {
16715                project.update(cx, |project, cx| {
16716                    project.stop_language_servers_for_buffers(
16717                        multi_buffer.all_buffers().into_iter().collect(),
16718                        HashSet::default(),
16719                        cx,
16720                    );
16721                    cx.emit(project::Event::RefreshInlayHints);
16722                });
16723            });
16724        }
16725    }
16726
16727    fn cancel_language_server_work(
16728        workspace: &mut Workspace,
16729        _: &actions::CancelLanguageServerWork,
16730        _: &mut Window,
16731        cx: &mut Context<Workspace>,
16732    ) {
16733        let project = workspace.project();
16734        let buffers = workspace
16735            .active_item(cx)
16736            .and_then(|item| item.act_as::<Editor>(cx))
16737            .map_or(HashSet::default(), |editor| {
16738                editor.read(cx).buffer.read(cx).all_buffers()
16739            });
16740        project.update(cx, |project, cx| {
16741            project.cancel_language_server_work_for_buffers(buffers, cx);
16742        });
16743    }
16744
16745    fn show_character_palette(
16746        &mut self,
16747        _: &ShowCharacterPalette,
16748        window: &mut Window,
16749        _: &mut Context<Self>,
16750    ) {
16751        window.show_character_palette();
16752    }
16753
16754    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16755        if !self.diagnostics_enabled() {
16756            return;
16757        }
16758
16759        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16760            let buffer = self.buffer.read(cx).snapshot(cx);
16761            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16762            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16763            let is_valid = buffer
16764                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16765                .any(|entry| {
16766                    entry.diagnostic.is_primary
16767                        && !entry.range.is_empty()
16768                        && entry.range.start == primary_range_start
16769                        && entry.diagnostic.message == active_diagnostics.active_message
16770                });
16771
16772            if !is_valid {
16773                self.dismiss_diagnostics(cx);
16774            }
16775        }
16776    }
16777
16778    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16779        match &self.active_diagnostics {
16780            ActiveDiagnostic::Group(group) => Some(group),
16781            _ => None,
16782        }
16783    }
16784
16785    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16786        if !self.diagnostics_enabled() {
16787            return;
16788        }
16789        self.dismiss_diagnostics(cx);
16790        self.active_diagnostics = ActiveDiagnostic::All;
16791    }
16792
16793    fn activate_diagnostics(
16794        &mut self,
16795        buffer_id: BufferId,
16796        diagnostic: DiagnosticEntry<usize>,
16797        window: &mut Window,
16798        cx: &mut Context<Self>,
16799    ) {
16800        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16801            return;
16802        }
16803        self.dismiss_diagnostics(cx);
16804        let snapshot = self.snapshot(window, cx);
16805        let buffer = self.buffer.read(cx).snapshot(cx);
16806        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16807            return;
16808        };
16809
16810        let diagnostic_group = buffer
16811            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16812            .collect::<Vec<_>>();
16813
16814        let blocks =
16815            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16816
16817        let blocks = self.display_map.update(cx, |display_map, cx| {
16818            display_map.insert_blocks(blocks, cx).into_iter().collect()
16819        });
16820        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16821            active_range: buffer.anchor_before(diagnostic.range.start)
16822                ..buffer.anchor_after(diagnostic.range.end),
16823            active_message: diagnostic.diagnostic.message.clone(),
16824            group_id: diagnostic.diagnostic.group_id,
16825            blocks,
16826        });
16827        cx.notify();
16828    }
16829
16830    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16831        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16832            return;
16833        };
16834
16835        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16836        if let ActiveDiagnostic::Group(group) = prev {
16837            self.display_map.update(cx, |display_map, cx| {
16838                display_map.remove_blocks(group.blocks, cx);
16839            });
16840            cx.notify();
16841        }
16842    }
16843
16844    /// Disable inline diagnostics rendering for this editor.
16845    pub fn disable_inline_diagnostics(&mut self) {
16846        self.inline_diagnostics_enabled = false;
16847        self.inline_diagnostics_update = Task::ready(());
16848        self.inline_diagnostics.clear();
16849    }
16850
16851    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16852        self.diagnostics_enabled = false;
16853        self.dismiss_diagnostics(cx);
16854        self.inline_diagnostics_update = Task::ready(());
16855        self.inline_diagnostics.clear();
16856    }
16857
16858    pub fn diagnostics_enabled(&self) -> bool {
16859        self.diagnostics_enabled && self.mode.is_full()
16860    }
16861
16862    pub fn inline_diagnostics_enabled(&self) -> bool {
16863        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16864    }
16865
16866    pub fn show_inline_diagnostics(&self) -> bool {
16867        self.show_inline_diagnostics
16868    }
16869
16870    pub fn toggle_inline_diagnostics(
16871        &mut self,
16872        _: &ToggleInlineDiagnostics,
16873        window: &mut Window,
16874        cx: &mut Context<Editor>,
16875    ) {
16876        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16877        self.refresh_inline_diagnostics(false, window, cx);
16878    }
16879
16880    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16881        self.diagnostics_max_severity = severity;
16882        self.display_map.update(cx, |display_map, _| {
16883            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16884        });
16885    }
16886
16887    pub fn toggle_diagnostics(
16888        &mut self,
16889        _: &ToggleDiagnostics,
16890        window: &mut Window,
16891        cx: &mut Context<Editor>,
16892    ) {
16893        if !self.diagnostics_enabled() {
16894            return;
16895        }
16896
16897        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16898            EditorSettings::get_global(cx)
16899                .diagnostics_max_severity
16900                .filter(|severity| severity != &DiagnosticSeverity::Off)
16901                .unwrap_or(DiagnosticSeverity::Hint)
16902        } else {
16903            DiagnosticSeverity::Off
16904        };
16905        self.set_max_diagnostics_severity(new_severity, cx);
16906        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16907            self.active_diagnostics = ActiveDiagnostic::None;
16908            self.inline_diagnostics_update = Task::ready(());
16909            self.inline_diagnostics.clear();
16910        } else {
16911            self.refresh_inline_diagnostics(false, window, cx);
16912        }
16913
16914        cx.notify();
16915    }
16916
16917    pub fn toggle_minimap(
16918        &mut self,
16919        _: &ToggleMinimap,
16920        window: &mut Window,
16921        cx: &mut Context<Editor>,
16922    ) {
16923        if self.supports_minimap(cx) {
16924            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16925        }
16926    }
16927
16928    fn refresh_inline_diagnostics(
16929        &mut self,
16930        debounce: bool,
16931        window: &mut Window,
16932        cx: &mut Context<Self>,
16933    ) {
16934        let max_severity = ProjectSettings::get_global(cx)
16935            .diagnostics
16936            .inline
16937            .max_severity
16938            .unwrap_or(self.diagnostics_max_severity);
16939
16940        if !self.inline_diagnostics_enabled()
16941            || !self.show_inline_diagnostics
16942            || max_severity == DiagnosticSeverity::Off
16943        {
16944            self.inline_diagnostics_update = Task::ready(());
16945            self.inline_diagnostics.clear();
16946            return;
16947        }
16948
16949        let debounce_ms = ProjectSettings::get_global(cx)
16950            .diagnostics
16951            .inline
16952            .update_debounce_ms;
16953        let debounce = if debounce && debounce_ms > 0 {
16954            Some(Duration::from_millis(debounce_ms))
16955        } else {
16956            None
16957        };
16958        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16959            if let Some(debounce) = debounce {
16960                cx.background_executor().timer(debounce).await;
16961            }
16962            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16963                editor
16964                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16965                    .ok()
16966            }) else {
16967                return;
16968            };
16969
16970            let new_inline_diagnostics = cx
16971                .background_spawn(async move {
16972                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16973                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16974                        let message = diagnostic_entry
16975                            .diagnostic
16976                            .message
16977                            .split_once('\n')
16978                            .map(|(line, _)| line)
16979                            .map(SharedString::new)
16980                            .unwrap_or_else(|| {
16981                                SharedString::from(diagnostic_entry.diagnostic.message)
16982                            });
16983                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16984                        let (Ok(i) | Err(i)) = inline_diagnostics
16985                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16986                        inline_diagnostics.insert(
16987                            i,
16988                            (
16989                                start_anchor,
16990                                InlineDiagnostic {
16991                                    message,
16992                                    group_id: diagnostic_entry.diagnostic.group_id,
16993                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16994                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16995                                    severity: diagnostic_entry.diagnostic.severity,
16996                                },
16997                            ),
16998                        );
16999                    }
17000                    inline_diagnostics
17001                })
17002                .await;
17003
17004            editor
17005                .update(cx, |editor, cx| {
17006                    editor.inline_diagnostics = new_inline_diagnostics;
17007                    cx.notify();
17008                })
17009                .ok();
17010        });
17011    }
17012
17013    fn pull_diagnostics(
17014        &mut self,
17015        buffer_id: Option<BufferId>,
17016        window: &Window,
17017        cx: &mut Context<Self>,
17018    ) -> Option<()> {
17019        if !self.mode().is_full() {
17020            return None;
17021        }
17022        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17023            .diagnostics
17024            .lsp_pull_diagnostics;
17025        if !pull_diagnostics_settings.enabled {
17026            return None;
17027        }
17028        let project = self.project.as_ref()?.downgrade();
17029        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17030        let mut buffers = self.buffer.read(cx).all_buffers();
17031        if let Some(buffer_id) = buffer_id {
17032            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17033        }
17034
17035        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17036            cx.background_executor().timer(debounce).await;
17037
17038            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17039                buffers
17040                    .into_iter()
17041                    .filter_map(|buffer| {
17042                        project
17043                            .update(cx, |project, cx| {
17044                                project.lsp_store().update(cx, |lsp_store, cx| {
17045                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17046                                })
17047                            })
17048                            .ok()
17049                    })
17050                    .collect::<FuturesUnordered<_>>()
17051            }) else {
17052                return;
17053            };
17054
17055            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17056                match pull_task {
17057                    Ok(()) => {
17058                        if editor
17059                            .update_in(cx, |editor, window, cx| {
17060                                editor.update_diagnostics_state(window, cx);
17061                            })
17062                            .is_err()
17063                        {
17064                            return;
17065                        }
17066                    }
17067                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17068                }
17069            }
17070        });
17071
17072        Some(())
17073    }
17074
17075    pub fn set_selections_from_remote(
17076        &mut self,
17077        selections: Vec<Selection<Anchor>>,
17078        pending_selection: Option<Selection<Anchor>>,
17079        window: &mut Window,
17080        cx: &mut Context<Self>,
17081    ) {
17082        let old_cursor_position = self.selections.newest_anchor().head();
17083        self.selections.change_with(cx, |s| {
17084            s.select_anchors(selections);
17085            if let Some(pending_selection) = pending_selection {
17086                s.set_pending(pending_selection, SelectMode::Character);
17087            } else {
17088                s.clear_pending();
17089            }
17090        });
17091        self.selections_did_change(
17092            false,
17093            &old_cursor_position,
17094            SelectionEffects::default(),
17095            window,
17096            cx,
17097        );
17098    }
17099
17100    pub fn transact(
17101        &mut self,
17102        window: &mut Window,
17103        cx: &mut Context<Self>,
17104        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17105    ) -> Option<TransactionId> {
17106        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17107            this.start_transaction_at(Instant::now(), window, cx);
17108            update(this, window, cx);
17109            this.end_transaction_at(Instant::now(), cx)
17110        })
17111    }
17112
17113    pub fn start_transaction_at(
17114        &mut self,
17115        now: Instant,
17116        window: &mut Window,
17117        cx: &mut Context<Self>,
17118    ) -> Option<TransactionId> {
17119        self.end_selection(window, cx);
17120        if let Some(tx_id) = self
17121            .buffer
17122            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17123        {
17124            self.selection_history
17125                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17126            cx.emit(EditorEvent::TransactionBegun {
17127                transaction_id: tx_id,
17128            });
17129            Some(tx_id)
17130        } else {
17131            None
17132        }
17133    }
17134
17135    pub fn end_transaction_at(
17136        &mut self,
17137        now: Instant,
17138        cx: &mut Context<Self>,
17139    ) -> Option<TransactionId> {
17140        if let Some(transaction_id) = self
17141            .buffer
17142            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17143        {
17144            if let Some((_, end_selections)) =
17145                self.selection_history.transaction_mut(transaction_id)
17146            {
17147                *end_selections = Some(self.selections.disjoint_anchors());
17148            } else {
17149                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17150            }
17151
17152            cx.emit(EditorEvent::Edited { transaction_id });
17153            Some(transaction_id)
17154        } else {
17155            None
17156        }
17157    }
17158
17159    pub fn modify_transaction_selection_history(
17160        &mut self,
17161        transaction_id: TransactionId,
17162        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17163    ) -> bool {
17164        self.selection_history
17165            .transaction_mut(transaction_id)
17166            .map(modify)
17167            .is_some()
17168    }
17169
17170    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17171        if self.selection_mark_mode {
17172            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17173                s.move_with(|_, sel| {
17174                    sel.collapse_to(sel.head(), SelectionGoal::None);
17175                });
17176            })
17177        }
17178        self.selection_mark_mode = true;
17179        cx.notify();
17180    }
17181
17182    pub fn swap_selection_ends(
17183        &mut self,
17184        _: &actions::SwapSelectionEnds,
17185        window: &mut Window,
17186        cx: &mut Context<Self>,
17187    ) {
17188        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17189            s.move_with(|_, sel| {
17190                if sel.start != sel.end {
17191                    sel.reversed = !sel.reversed
17192                }
17193            });
17194        });
17195        self.request_autoscroll(Autoscroll::newest(), cx);
17196        cx.notify();
17197    }
17198
17199    pub fn toggle_focus(
17200        workspace: &mut Workspace,
17201        _: &actions::ToggleFocus,
17202        window: &mut Window,
17203        cx: &mut Context<Workspace>,
17204    ) {
17205        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17206            return;
17207        };
17208        workspace.activate_item(&item, true, true, window, cx);
17209    }
17210
17211    pub fn toggle_fold(
17212        &mut self,
17213        _: &actions::ToggleFold,
17214        window: &mut Window,
17215        cx: &mut Context<Self>,
17216    ) {
17217        if self.is_singleton(cx) {
17218            let selection = self.selections.newest::<Point>(cx);
17219
17220            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17221            let range = if selection.is_empty() {
17222                let point = selection.head().to_display_point(&display_map);
17223                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17224                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17225                    .to_point(&display_map);
17226                start..end
17227            } else {
17228                selection.range()
17229            };
17230            if display_map.folds_in_range(range).next().is_some() {
17231                self.unfold_lines(&Default::default(), window, cx)
17232            } else {
17233                self.fold(&Default::default(), window, cx)
17234            }
17235        } else {
17236            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17237            let buffer_ids: HashSet<_> = self
17238                .selections
17239                .disjoint_anchor_ranges()
17240                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17241                .collect();
17242
17243            let should_unfold = buffer_ids
17244                .iter()
17245                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17246
17247            for buffer_id in buffer_ids {
17248                if should_unfold {
17249                    self.unfold_buffer(buffer_id, cx);
17250                } else {
17251                    self.fold_buffer(buffer_id, cx);
17252                }
17253            }
17254        }
17255    }
17256
17257    pub fn toggle_fold_recursive(
17258        &mut self,
17259        _: &actions::ToggleFoldRecursive,
17260        window: &mut Window,
17261        cx: &mut Context<Self>,
17262    ) {
17263        let selection = self.selections.newest::<Point>(cx);
17264
17265        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17266        let range = if selection.is_empty() {
17267            let point = selection.head().to_display_point(&display_map);
17268            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17269            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17270                .to_point(&display_map);
17271            start..end
17272        } else {
17273            selection.range()
17274        };
17275        if display_map.folds_in_range(range).next().is_some() {
17276            self.unfold_recursive(&Default::default(), window, cx)
17277        } else {
17278            self.fold_recursive(&Default::default(), window, cx)
17279        }
17280    }
17281
17282    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17283        if self.is_singleton(cx) {
17284            let mut to_fold = Vec::new();
17285            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17286            let selections = self.selections.all_adjusted(cx);
17287
17288            for selection in selections {
17289                let range = selection.range().sorted();
17290                let buffer_start_row = range.start.row;
17291
17292                if range.start.row != range.end.row {
17293                    let mut found = false;
17294                    let mut row = range.start.row;
17295                    while row <= range.end.row {
17296                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17297                        {
17298                            found = true;
17299                            row = crease.range().end.row + 1;
17300                            to_fold.push(crease);
17301                        } else {
17302                            row += 1
17303                        }
17304                    }
17305                    if found {
17306                        continue;
17307                    }
17308                }
17309
17310                for row in (0..=range.start.row).rev() {
17311                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17312                        if crease.range().end.row >= buffer_start_row {
17313                            to_fold.push(crease);
17314                            if row <= range.start.row {
17315                                break;
17316                            }
17317                        }
17318                    }
17319                }
17320            }
17321
17322            self.fold_creases(to_fold, true, window, cx);
17323        } else {
17324            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17325            let buffer_ids = self
17326                .selections
17327                .disjoint_anchor_ranges()
17328                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17329                .collect::<HashSet<_>>();
17330            for buffer_id in buffer_ids {
17331                self.fold_buffer(buffer_id, cx);
17332            }
17333        }
17334    }
17335
17336    pub fn toggle_fold_all(
17337        &mut self,
17338        _: &actions::ToggleFoldAll,
17339        window: &mut Window,
17340        cx: &mut Context<Self>,
17341    ) {
17342        if self.buffer.read(cx).is_singleton() {
17343            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17344            let has_folds = display_map
17345                .folds_in_range(0..display_map.buffer_snapshot.len())
17346                .next()
17347                .is_some();
17348
17349            if has_folds {
17350                self.unfold_all(&actions::UnfoldAll, window, cx);
17351            } else {
17352                self.fold_all(&actions::FoldAll, window, cx);
17353            }
17354        } else {
17355            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17356            let should_unfold = buffer_ids
17357                .iter()
17358                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17359
17360            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17361                editor
17362                    .update_in(cx, |editor, _, cx| {
17363                        for buffer_id in buffer_ids {
17364                            if should_unfold {
17365                                editor.unfold_buffer(buffer_id, cx);
17366                            } else {
17367                                editor.fold_buffer(buffer_id, cx);
17368                            }
17369                        }
17370                    })
17371                    .ok();
17372            });
17373        }
17374    }
17375
17376    fn fold_at_level(
17377        &mut self,
17378        fold_at: &FoldAtLevel,
17379        window: &mut Window,
17380        cx: &mut Context<Self>,
17381    ) {
17382        if !self.buffer.read(cx).is_singleton() {
17383            return;
17384        }
17385
17386        let fold_at_level = fold_at.0;
17387        let snapshot = self.buffer.read(cx).snapshot(cx);
17388        let mut to_fold = Vec::new();
17389        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17390
17391        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17392            while start_row < end_row {
17393                match self
17394                    .snapshot(window, cx)
17395                    .crease_for_buffer_row(MultiBufferRow(start_row))
17396                {
17397                    Some(crease) => {
17398                        let nested_start_row = crease.range().start.row + 1;
17399                        let nested_end_row = crease.range().end.row;
17400
17401                        if current_level < fold_at_level {
17402                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17403                        } else if current_level == fold_at_level {
17404                            to_fold.push(crease);
17405                        }
17406
17407                        start_row = nested_end_row + 1;
17408                    }
17409                    None => start_row += 1,
17410                }
17411            }
17412        }
17413
17414        self.fold_creases(to_fold, true, window, cx);
17415    }
17416
17417    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17418        if self.buffer.read(cx).is_singleton() {
17419            let mut fold_ranges = Vec::new();
17420            let snapshot = self.buffer.read(cx).snapshot(cx);
17421
17422            for row in 0..snapshot.max_row().0 {
17423                if let Some(foldable_range) = self
17424                    .snapshot(window, cx)
17425                    .crease_for_buffer_row(MultiBufferRow(row))
17426                {
17427                    fold_ranges.push(foldable_range);
17428                }
17429            }
17430
17431            self.fold_creases(fold_ranges, true, window, cx);
17432        } else {
17433            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17434                editor
17435                    .update_in(cx, |editor, _, cx| {
17436                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17437                            editor.fold_buffer(buffer_id, cx);
17438                        }
17439                    })
17440                    .ok();
17441            });
17442        }
17443    }
17444
17445    pub fn fold_function_bodies(
17446        &mut self,
17447        _: &actions::FoldFunctionBodies,
17448        window: &mut Window,
17449        cx: &mut Context<Self>,
17450    ) {
17451        let snapshot = self.buffer.read(cx).snapshot(cx);
17452
17453        let ranges = snapshot
17454            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17455            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17456            .collect::<Vec<_>>();
17457
17458        let creases = ranges
17459            .into_iter()
17460            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17461            .collect();
17462
17463        self.fold_creases(creases, true, window, cx);
17464    }
17465
17466    pub fn fold_recursive(
17467        &mut self,
17468        _: &actions::FoldRecursive,
17469        window: &mut Window,
17470        cx: &mut Context<Self>,
17471    ) {
17472        let mut to_fold = Vec::new();
17473        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17474        let selections = self.selections.all_adjusted(cx);
17475
17476        for selection in selections {
17477            let range = selection.range().sorted();
17478            let buffer_start_row = range.start.row;
17479
17480            if range.start.row != range.end.row {
17481                let mut found = false;
17482                for row in range.start.row..=range.end.row {
17483                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17484                        found = true;
17485                        to_fold.push(crease);
17486                    }
17487                }
17488                if found {
17489                    continue;
17490                }
17491            }
17492
17493            for row in (0..=range.start.row).rev() {
17494                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17495                    if crease.range().end.row >= buffer_start_row {
17496                        to_fold.push(crease);
17497                    } else {
17498                        break;
17499                    }
17500                }
17501            }
17502        }
17503
17504        self.fold_creases(to_fold, true, window, cx);
17505    }
17506
17507    pub fn fold_at(
17508        &mut self,
17509        buffer_row: MultiBufferRow,
17510        window: &mut Window,
17511        cx: &mut Context<Self>,
17512    ) {
17513        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17514
17515        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17516            let autoscroll = self
17517                .selections
17518                .all::<Point>(cx)
17519                .iter()
17520                .any(|selection| crease.range().overlaps(&selection.range()));
17521
17522            self.fold_creases(vec![crease], autoscroll, window, cx);
17523        }
17524    }
17525
17526    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17527        if self.is_singleton(cx) {
17528            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17529            let buffer = &display_map.buffer_snapshot;
17530            let selections = self.selections.all::<Point>(cx);
17531            let ranges = selections
17532                .iter()
17533                .map(|s| {
17534                    let range = s.display_range(&display_map).sorted();
17535                    let mut start = range.start.to_point(&display_map);
17536                    let mut end = range.end.to_point(&display_map);
17537                    start.column = 0;
17538                    end.column = buffer.line_len(MultiBufferRow(end.row));
17539                    start..end
17540                })
17541                .collect::<Vec<_>>();
17542
17543            self.unfold_ranges(&ranges, true, true, cx);
17544        } else {
17545            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17546            let buffer_ids = self
17547                .selections
17548                .disjoint_anchor_ranges()
17549                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17550                .collect::<HashSet<_>>();
17551            for buffer_id in buffer_ids {
17552                self.unfold_buffer(buffer_id, cx);
17553            }
17554        }
17555    }
17556
17557    pub fn unfold_recursive(
17558        &mut self,
17559        _: &UnfoldRecursive,
17560        _window: &mut Window,
17561        cx: &mut Context<Self>,
17562    ) {
17563        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17564        let selections = self.selections.all::<Point>(cx);
17565        let ranges = selections
17566            .iter()
17567            .map(|s| {
17568                let mut range = s.display_range(&display_map).sorted();
17569                *range.start.column_mut() = 0;
17570                *range.end.column_mut() = display_map.line_len(range.end.row());
17571                let start = range.start.to_point(&display_map);
17572                let end = range.end.to_point(&display_map);
17573                start..end
17574            })
17575            .collect::<Vec<_>>();
17576
17577        self.unfold_ranges(&ranges, true, true, cx);
17578    }
17579
17580    pub fn unfold_at(
17581        &mut self,
17582        buffer_row: MultiBufferRow,
17583        _window: &mut Window,
17584        cx: &mut Context<Self>,
17585    ) {
17586        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17587
17588        let intersection_range = Point::new(buffer_row.0, 0)
17589            ..Point::new(
17590                buffer_row.0,
17591                display_map.buffer_snapshot.line_len(buffer_row),
17592            );
17593
17594        let autoscroll = self
17595            .selections
17596            .all::<Point>(cx)
17597            .iter()
17598            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17599
17600        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17601    }
17602
17603    pub fn unfold_all(
17604        &mut self,
17605        _: &actions::UnfoldAll,
17606        _window: &mut Window,
17607        cx: &mut Context<Self>,
17608    ) {
17609        if self.buffer.read(cx).is_singleton() {
17610            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17611            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17612        } else {
17613            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17614                editor
17615                    .update(cx, |editor, cx| {
17616                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17617                            editor.unfold_buffer(buffer_id, cx);
17618                        }
17619                    })
17620                    .ok();
17621            });
17622        }
17623    }
17624
17625    pub fn fold_selected_ranges(
17626        &mut self,
17627        _: &FoldSelectedRanges,
17628        window: &mut Window,
17629        cx: &mut Context<Self>,
17630    ) {
17631        let selections = self.selections.all_adjusted(cx);
17632        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17633        let ranges = selections
17634            .into_iter()
17635            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17636            .collect::<Vec<_>>();
17637        self.fold_creases(ranges, true, window, cx);
17638    }
17639
17640    pub fn fold_ranges<T: ToOffset + Clone>(
17641        &mut self,
17642        ranges: Vec<Range<T>>,
17643        auto_scroll: bool,
17644        window: &mut Window,
17645        cx: &mut Context<Self>,
17646    ) {
17647        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17648        let ranges = ranges
17649            .into_iter()
17650            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17651            .collect::<Vec<_>>();
17652        self.fold_creases(ranges, auto_scroll, window, cx);
17653    }
17654
17655    pub fn fold_creases<T: ToOffset + Clone>(
17656        &mut self,
17657        creases: Vec<Crease<T>>,
17658        auto_scroll: bool,
17659        _window: &mut Window,
17660        cx: &mut Context<Self>,
17661    ) {
17662        if creases.is_empty() {
17663            return;
17664        }
17665
17666        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17667
17668        if auto_scroll {
17669            self.request_autoscroll(Autoscroll::fit(), cx);
17670        }
17671
17672        cx.notify();
17673
17674        self.scrollbar_marker_state.dirty = true;
17675        self.folds_did_change(cx);
17676    }
17677
17678    /// Removes any folds whose ranges intersect any of the given ranges.
17679    pub fn unfold_ranges<T: ToOffset + Clone>(
17680        &mut self,
17681        ranges: &[Range<T>],
17682        inclusive: bool,
17683        auto_scroll: bool,
17684        cx: &mut Context<Self>,
17685    ) {
17686        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17687            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17688        });
17689        self.folds_did_change(cx);
17690    }
17691
17692    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17693        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17694            return;
17695        }
17696        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17697        self.display_map.update(cx, |display_map, cx| {
17698            display_map.fold_buffers([buffer_id], cx)
17699        });
17700        cx.emit(EditorEvent::BufferFoldToggled {
17701            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17702            folded: true,
17703        });
17704        cx.notify();
17705    }
17706
17707    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17708        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17709            return;
17710        }
17711        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17712        self.display_map.update(cx, |display_map, cx| {
17713            display_map.unfold_buffers([buffer_id], cx);
17714        });
17715        cx.emit(EditorEvent::BufferFoldToggled {
17716            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17717            folded: false,
17718        });
17719        cx.notify();
17720    }
17721
17722    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17723        self.display_map.read(cx).is_buffer_folded(buffer)
17724    }
17725
17726    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17727        self.display_map.read(cx).folded_buffers()
17728    }
17729
17730    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17731        self.display_map.update(cx, |display_map, cx| {
17732            display_map.disable_header_for_buffer(buffer_id, cx);
17733        });
17734        cx.notify();
17735    }
17736
17737    /// Removes any folds with the given ranges.
17738    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17739        &mut self,
17740        ranges: &[Range<T>],
17741        type_id: TypeId,
17742        auto_scroll: bool,
17743        cx: &mut Context<Self>,
17744    ) {
17745        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17746            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17747        });
17748        self.folds_did_change(cx);
17749    }
17750
17751    fn remove_folds_with<T: ToOffset + Clone>(
17752        &mut self,
17753        ranges: &[Range<T>],
17754        auto_scroll: bool,
17755        cx: &mut Context<Self>,
17756        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17757    ) {
17758        if ranges.is_empty() {
17759            return;
17760        }
17761
17762        let mut buffers_affected = HashSet::default();
17763        let multi_buffer = self.buffer().read(cx);
17764        for range in ranges {
17765            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17766                buffers_affected.insert(buffer.read(cx).remote_id());
17767            };
17768        }
17769
17770        self.display_map.update(cx, update);
17771
17772        if auto_scroll {
17773            self.request_autoscroll(Autoscroll::fit(), cx);
17774        }
17775
17776        cx.notify();
17777        self.scrollbar_marker_state.dirty = true;
17778        self.active_indent_guides_state.dirty = true;
17779    }
17780
17781    pub fn update_renderer_widths(
17782        &mut self,
17783        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17784        cx: &mut Context<Self>,
17785    ) -> bool {
17786        self.display_map
17787            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17788    }
17789
17790    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17791        self.display_map.read(cx).fold_placeholder.clone()
17792    }
17793
17794    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17795        self.buffer.update(cx, |buffer, cx| {
17796            buffer.set_all_diff_hunks_expanded(cx);
17797        });
17798    }
17799
17800    pub fn expand_all_diff_hunks(
17801        &mut self,
17802        _: &ExpandAllDiffHunks,
17803        _window: &mut Window,
17804        cx: &mut Context<Self>,
17805    ) {
17806        self.buffer.update(cx, |buffer, cx| {
17807            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17808        });
17809    }
17810
17811    pub fn toggle_selected_diff_hunks(
17812        &mut self,
17813        _: &ToggleSelectedDiffHunks,
17814        _window: &mut Window,
17815        cx: &mut Context<Self>,
17816    ) {
17817        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17818        self.toggle_diff_hunks_in_ranges(ranges, cx);
17819    }
17820
17821    pub fn diff_hunks_in_ranges<'a>(
17822        &'a self,
17823        ranges: &'a [Range<Anchor>],
17824        buffer: &'a MultiBufferSnapshot,
17825    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17826        ranges.iter().flat_map(move |range| {
17827            let end_excerpt_id = range.end.excerpt_id;
17828            let range = range.to_point(buffer);
17829            let mut peek_end = range.end;
17830            if range.end.row < buffer.max_row().0 {
17831                peek_end = Point::new(range.end.row + 1, 0);
17832            }
17833            buffer
17834                .diff_hunks_in_range(range.start..peek_end)
17835                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17836        })
17837    }
17838
17839    pub fn has_stageable_diff_hunks_in_ranges(
17840        &self,
17841        ranges: &[Range<Anchor>],
17842        snapshot: &MultiBufferSnapshot,
17843    ) -> bool {
17844        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17845        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17846    }
17847
17848    pub fn toggle_staged_selected_diff_hunks(
17849        &mut self,
17850        _: &::git::ToggleStaged,
17851        _: &mut Window,
17852        cx: &mut Context<Self>,
17853    ) {
17854        let snapshot = self.buffer.read(cx).snapshot(cx);
17855        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17856        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17857        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17858    }
17859
17860    pub fn set_render_diff_hunk_controls(
17861        &mut self,
17862        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17863        cx: &mut Context<Self>,
17864    ) {
17865        self.render_diff_hunk_controls = render_diff_hunk_controls;
17866        cx.notify();
17867    }
17868
17869    pub fn stage_and_next(
17870        &mut self,
17871        _: &::git::StageAndNext,
17872        window: &mut Window,
17873        cx: &mut Context<Self>,
17874    ) {
17875        self.do_stage_or_unstage_and_next(true, window, cx);
17876    }
17877
17878    pub fn unstage_and_next(
17879        &mut self,
17880        _: &::git::UnstageAndNext,
17881        window: &mut Window,
17882        cx: &mut Context<Self>,
17883    ) {
17884        self.do_stage_or_unstage_and_next(false, window, cx);
17885    }
17886
17887    pub fn stage_or_unstage_diff_hunks(
17888        &mut self,
17889        stage: bool,
17890        ranges: Vec<Range<Anchor>>,
17891        cx: &mut Context<Self>,
17892    ) {
17893        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17894        cx.spawn(async move |this, cx| {
17895            task.await?;
17896            this.update(cx, |this, cx| {
17897                let snapshot = this.buffer.read(cx).snapshot(cx);
17898                let chunk_by = this
17899                    .diff_hunks_in_ranges(&ranges, &snapshot)
17900                    .chunk_by(|hunk| hunk.buffer_id);
17901                for (buffer_id, hunks) in &chunk_by {
17902                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17903                }
17904            })
17905        })
17906        .detach_and_log_err(cx);
17907    }
17908
17909    fn save_buffers_for_ranges_if_needed(
17910        &mut self,
17911        ranges: &[Range<Anchor>],
17912        cx: &mut Context<Editor>,
17913    ) -> Task<Result<()>> {
17914        let multibuffer = self.buffer.read(cx);
17915        let snapshot = multibuffer.read(cx);
17916        let buffer_ids: HashSet<_> = ranges
17917            .iter()
17918            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17919            .collect();
17920        drop(snapshot);
17921
17922        let mut buffers = HashSet::default();
17923        for buffer_id in buffer_ids {
17924            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17925                let buffer = buffer_entity.read(cx);
17926                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17927                {
17928                    buffers.insert(buffer_entity);
17929                }
17930            }
17931        }
17932
17933        if let Some(project) = &self.project {
17934            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17935        } else {
17936            Task::ready(Ok(()))
17937        }
17938    }
17939
17940    fn do_stage_or_unstage_and_next(
17941        &mut self,
17942        stage: bool,
17943        window: &mut Window,
17944        cx: &mut Context<Self>,
17945    ) {
17946        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17947
17948        if ranges.iter().any(|range| range.start != range.end) {
17949            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17950            return;
17951        }
17952
17953        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17954        let snapshot = self.snapshot(window, cx);
17955        let position = self.selections.newest::<Point>(cx).head();
17956        let mut row = snapshot
17957            .buffer_snapshot
17958            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17959            .find(|hunk| hunk.row_range.start.0 > position.row)
17960            .map(|hunk| hunk.row_range.start);
17961
17962        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17963        // Outside of the project diff editor, wrap around to the beginning.
17964        if !all_diff_hunks_expanded {
17965            row = row.or_else(|| {
17966                snapshot
17967                    .buffer_snapshot
17968                    .diff_hunks_in_range(Point::zero()..position)
17969                    .find(|hunk| hunk.row_range.end.0 < position.row)
17970                    .map(|hunk| hunk.row_range.start)
17971            });
17972        }
17973
17974        if let Some(row) = row {
17975            let destination = Point::new(row.0, 0);
17976            let autoscroll = Autoscroll::center();
17977
17978            self.unfold_ranges(&[destination..destination], false, false, cx);
17979            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17980                s.select_ranges([destination..destination]);
17981            });
17982        }
17983    }
17984
17985    fn do_stage_or_unstage(
17986        &self,
17987        stage: bool,
17988        buffer_id: BufferId,
17989        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17990        cx: &mut App,
17991    ) -> Option<()> {
17992        let project = self.project.as_ref()?;
17993        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17994        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17995        let buffer_snapshot = buffer.read(cx).snapshot();
17996        let file_exists = buffer_snapshot
17997            .file()
17998            .is_some_and(|file| file.disk_state().exists());
17999        diff.update(cx, |diff, cx| {
18000            diff.stage_or_unstage_hunks(
18001                stage,
18002                &hunks
18003                    .map(|hunk| buffer_diff::DiffHunk {
18004                        buffer_range: hunk.buffer_range,
18005                        diff_base_byte_range: hunk.diff_base_byte_range,
18006                        secondary_status: hunk.secondary_status,
18007                        range: Point::zero()..Point::zero(), // unused
18008                    })
18009                    .collect::<Vec<_>>(),
18010                &buffer_snapshot,
18011                file_exists,
18012                cx,
18013            )
18014        });
18015        None
18016    }
18017
18018    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18019        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18020        self.buffer
18021            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18022    }
18023
18024    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18025        self.buffer.update(cx, |buffer, cx| {
18026            let ranges = vec![Anchor::min()..Anchor::max()];
18027            if !buffer.all_diff_hunks_expanded()
18028                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18029            {
18030                buffer.collapse_diff_hunks(ranges, cx);
18031                true
18032            } else {
18033                false
18034            }
18035        })
18036    }
18037
18038    fn toggle_diff_hunks_in_ranges(
18039        &mut self,
18040        ranges: Vec<Range<Anchor>>,
18041        cx: &mut Context<Editor>,
18042    ) {
18043        self.buffer.update(cx, |buffer, cx| {
18044            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18045            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18046        })
18047    }
18048
18049    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18050        self.buffer.update(cx, |buffer, cx| {
18051            let snapshot = buffer.snapshot(cx);
18052            let excerpt_id = range.end.excerpt_id;
18053            let point_range = range.to_point(&snapshot);
18054            let expand = !buffer.single_hunk_is_expanded(range, cx);
18055            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18056        })
18057    }
18058
18059    pub(crate) fn apply_all_diff_hunks(
18060        &mut self,
18061        _: &ApplyAllDiffHunks,
18062        window: &mut Window,
18063        cx: &mut Context<Self>,
18064    ) {
18065        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18066
18067        let buffers = self.buffer.read(cx).all_buffers();
18068        for branch_buffer in buffers {
18069            branch_buffer.update(cx, |branch_buffer, cx| {
18070                branch_buffer.merge_into_base(Vec::new(), cx);
18071            });
18072        }
18073
18074        if let Some(project) = self.project.clone() {
18075            self.save(
18076                SaveOptions {
18077                    format: true,
18078                    autosave: false,
18079                },
18080                project,
18081                window,
18082                cx,
18083            )
18084            .detach_and_log_err(cx);
18085        }
18086    }
18087
18088    pub(crate) fn apply_selected_diff_hunks(
18089        &mut self,
18090        _: &ApplyDiffHunk,
18091        window: &mut Window,
18092        cx: &mut Context<Self>,
18093    ) {
18094        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18095        let snapshot = self.snapshot(window, cx);
18096        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18097        let mut ranges_by_buffer = HashMap::default();
18098        self.transact(window, cx, |editor, _window, cx| {
18099            for hunk in hunks {
18100                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18101                    ranges_by_buffer
18102                        .entry(buffer.clone())
18103                        .or_insert_with(Vec::new)
18104                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18105                }
18106            }
18107
18108            for (buffer, ranges) in ranges_by_buffer {
18109                buffer.update(cx, |buffer, cx| {
18110                    buffer.merge_into_base(ranges, cx);
18111                });
18112            }
18113        });
18114
18115        if let Some(project) = self.project.clone() {
18116            self.save(
18117                SaveOptions {
18118                    format: true,
18119                    autosave: false,
18120                },
18121                project,
18122                window,
18123                cx,
18124            )
18125            .detach_and_log_err(cx);
18126        }
18127    }
18128
18129    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18130        if hovered != self.gutter_hovered {
18131            self.gutter_hovered = hovered;
18132            cx.notify();
18133        }
18134    }
18135
18136    pub fn insert_blocks(
18137        &mut self,
18138        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18139        autoscroll: Option<Autoscroll>,
18140        cx: &mut Context<Self>,
18141    ) -> Vec<CustomBlockId> {
18142        let blocks = self
18143            .display_map
18144            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18145        if let Some(autoscroll) = autoscroll {
18146            self.request_autoscroll(autoscroll, cx);
18147        }
18148        cx.notify();
18149        blocks
18150    }
18151
18152    pub fn resize_blocks(
18153        &mut self,
18154        heights: HashMap<CustomBlockId, u32>,
18155        autoscroll: Option<Autoscroll>,
18156        cx: &mut Context<Self>,
18157    ) {
18158        self.display_map
18159            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18160        if let Some(autoscroll) = autoscroll {
18161            self.request_autoscroll(autoscroll, cx);
18162        }
18163        cx.notify();
18164    }
18165
18166    pub fn replace_blocks(
18167        &mut self,
18168        renderers: HashMap<CustomBlockId, RenderBlock>,
18169        autoscroll: Option<Autoscroll>,
18170        cx: &mut Context<Self>,
18171    ) {
18172        self.display_map
18173            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18174        if let Some(autoscroll) = autoscroll {
18175            self.request_autoscroll(autoscroll, cx);
18176        }
18177        cx.notify();
18178    }
18179
18180    pub fn remove_blocks(
18181        &mut self,
18182        block_ids: HashSet<CustomBlockId>,
18183        autoscroll: Option<Autoscroll>,
18184        cx: &mut Context<Self>,
18185    ) {
18186        self.display_map.update(cx, |display_map, cx| {
18187            display_map.remove_blocks(block_ids, cx)
18188        });
18189        if let Some(autoscroll) = autoscroll {
18190            self.request_autoscroll(autoscroll, cx);
18191        }
18192        cx.notify();
18193    }
18194
18195    pub fn row_for_block(
18196        &self,
18197        block_id: CustomBlockId,
18198        cx: &mut Context<Self>,
18199    ) -> Option<DisplayRow> {
18200        self.display_map
18201            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18202    }
18203
18204    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18205        self.focused_block = Some(focused_block);
18206    }
18207
18208    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18209        self.focused_block.take()
18210    }
18211
18212    pub fn insert_creases(
18213        &mut self,
18214        creases: impl IntoIterator<Item = Crease<Anchor>>,
18215        cx: &mut Context<Self>,
18216    ) -> Vec<CreaseId> {
18217        self.display_map
18218            .update(cx, |map, cx| map.insert_creases(creases, cx))
18219    }
18220
18221    pub fn remove_creases(
18222        &mut self,
18223        ids: impl IntoIterator<Item = CreaseId>,
18224        cx: &mut Context<Self>,
18225    ) -> Vec<(CreaseId, Range<Anchor>)> {
18226        self.display_map
18227            .update(cx, |map, cx| map.remove_creases(ids, cx))
18228    }
18229
18230    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18231        self.display_map
18232            .update(cx, |map, cx| map.snapshot(cx))
18233            .longest_row()
18234    }
18235
18236    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18237        self.display_map
18238            .update(cx, |map, cx| map.snapshot(cx))
18239            .max_point()
18240    }
18241
18242    pub fn text(&self, cx: &App) -> String {
18243        self.buffer.read(cx).read(cx).text()
18244    }
18245
18246    pub fn is_empty(&self, cx: &App) -> bool {
18247        self.buffer.read(cx).read(cx).is_empty()
18248    }
18249
18250    pub fn text_option(&self, cx: &App) -> Option<String> {
18251        let text = self.text(cx);
18252        let text = text.trim();
18253
18254        if text.is_empty() {
18255            return None;
18256        }
18257
18258        Some(text.to_string())
18259    }
18260
18261    pub fn set_text(
18262        &mut self,
18263        text: impl Into<Arc<str>>,
18264        window: &mut Window,
18265        cx: &mut Context<Self>,
18266    ) {
18267        self.transact(window, cx, |this, _, cx| {
18268            this.buffer
18269                .read(cx)
18270                .as_singleton()
18271                .expect("you can only call set_text on editors for singleton buffers")
18272                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18273        });
18274    }
18275
18276    pub fn display_text(&self, cx: &mut App) -> String {
18277        self.display_map
18278            .update(cx, |map, cx| map.snapshot(cx))
18279            .text()
18280    }
18281
18282    fn create_minimap(
18283        &self,
18284        minimap_settings: MinimapSettings,
18285        window: &mut Window,
18286        cx: &mut Context<Self>,
18287    ) -> Option<Entity<Self>> {
18288        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18289            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18290    }
18291
18292    fn initialize_new_minimap(
18293        &self,
18294        minimap_settings: MinimapSettings,
18295        window: &mut Window,
18296        cx: &mut Context<Self>,
18297    ) -> Entity<Self> {
18298        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18299
18300        let mut minimap = Editor::new_internal(
18301            EditorMode::Minimap {
18302                parent: cx.weak_entity(),
18303            },
18304            self.buffer.clone(),
18305            None,
18306            Some(self.display_map.clone()),
18307            window,
18308            cx,
18309        );
18310        minimap.scroll_manager.clone_state(&self.scroll_manager);
18311        minimap.set_text_style_refinement(TextStyleRefinement {
18312            font_size: Some(MINIMAP_FONT_SIZE),
18313            font_weight: Some(MINIMAP_FONT_WEIGHT),
18314            ..Default::default()
18315        });
18316        minimap.update_minimap_configuration(minimap_settings, cx);
18317        cx.new(|_| minimap)
18318    }
18319
18320    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18321        let current_line_highlight = minimap_settings
18322            .current_line_highlight
18323            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18324        self.set_current_line_highlight(Some(current_line_highlight));
18325    }
18326
18327    pub fn minimap(&self) -> Option<&Entity<Self>> {
18328        self.minimap
18329            .as_ref()
18330            .filter(|_| self.minimap_visibility.visible())
18331    }
18332
18333    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18334        let mut wrap_guides = smallvec![];
18335
18336        if self.show_wrap_guides == Some(false) {
18337            return wrap_guides;
18338        }
18339
18340        let settings = self.buffer.read(cx).language_settings(cx);
18341        if settings.show_wrap_guides {
18342            match self.soft_wrap_mode(cx) {
18343                SoftWrap::Column(soft_wrap) => {
18344                    wrap_guides.push((soft_wrap as usize, true));
18345                }
18346                SoftWrap::Bounded(soft_wrap) => {
18347                    wrap_guides.push((soft_wrap as usize, true));
18348                }
18349                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18350            }
18351            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18352        }
18353
18354        wrap_guides
18355    }
18356
18357    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18358        let settings = self.buffer.read(cx).language_settings(cx);
18359        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18360        match mode {
18361            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18362                SoftWrap::None
18363            }
18364            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18365            language_settings::SoftWrap::PreferredLineLength => {
18366                SoftWrap::Column(settings.preferred_line_length)
18367            }
18368            language_settings::SoftWrap::Bounded => {
18369                SoftWrap::Bounded(settings.preferred_line_length)
18370            }
18371        }
18372    }
18373
18374    pub fn set_soft_wrap_mode(
18375        &mut self,
18376        mode: language_settings::SoftWrap,
18377
18378        cx: &mut Context<Self>,
18379    ) {
18380        self.soft_wrap_mode_override = Some(mode);
18381        cx.notify();
18382    }
18383
18384    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18385        self.hard_wrap = hard_wrap;
18386        cx.notify();
18387    }
18388
18389    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18390        self.text_style_refinement = Some(style);
18391    }
18392
18393    /// called by the Element so we know what style we were most recently rendered with.
18394    pub(crate) fn set_style(
18395        &mut self,
18396        style: EditorStyle,
18397        window: &mut Window,
18398        cx: &mut Context<Self>,
18399    ) {
18400        // We intentionally do not inform the display map about the minimap style
18401        // so that wrapping is not recalculated and stays consistent for the editor
18402        // and its linked minimap.
18403        if !self.mode.is_minimap() {
18404            let rem_size = window.rem_size();
18405            self.display_map.update(cx, |map, cx| {
18406                map.set_font(
18407                    style.text.font(),
18408                    style.text.font_size.to_pixels(rem_size),
18409                    cx,
18410                )
18411            });
18412        }
18413        self.style = Some(style);
18414    }
18415
18416    pub fn style(&self) -> Option<&EditorStyle> {
18417        self.style.as_ref()
18418    }
18419
18420    // Called by the element. This method is not designed to be called outside of the editor
18421    // element's layout code because it does not notify when rewrapping is computed synchronously.
18422    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18423        self.display_map
18424            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18425    }
18426
18427    pub fn set_soft_wrap(&mut self) {
18428        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18429    }
18430
18431    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18432        if self.soft_wrap_mode_override.is_some() {
18433            self.soft_wrap_mode_override.take();
18434        } else {
18435            let soft_wrap = match self.soft_wrap_mode(cx) {
18436                SoftWrap::GitDiff => return,
18437                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18438                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18439                    language_settings::SoftWrap::None
18440                }
18441            };
18442            self.soft_wrap_mode_override = Some(soft_wrap);
18443        }
18444        cx.notify();
18445    }
18446
18447    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18448        let Some(workspace) = self.workspace() else {
18449            return;
18450        };
18451        let fs = workspace.read(cx).app_state().fs.clone();
18452        let current_show = TabBarSettings::get_global(cx).show;
18453        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18454            setting.show = Some(!current_show);
18455        });
18456    }
18457
18458    pub fn toggle_indent_guides(
18459        &mut self,
18460        _: &ToggleIndentGuides,
18461        _: &mut Window,
18462        cx: &mut Context<Self>,
18463    ) {
18464        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18465            self.buffer
18466                .read(cx)
18467                .language_settings(cx)
18468                .indent_guides
18469                .enabled
18470        });
18471        self.show_indent_guides = Some(!currently_enabled);
18472        cx.notify();
18473    }
18474
18475    fn should_show_indent_guides(&self) -> Option<bool> {
18476        self.show_indent_guides
18477    }
18478
18479    pub fn toggle_line_numbers(
18480        &mut self,
18481        _: &ToggleLineNumbers,
18482        _: &mut Window,
18483        cx: &mut Context<Self>,
18484    ) {
18485        let mut editor_settings = EditorSettings::get_global(cx).clone();
18486        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18487        EditorSettings::override_global(editor_settings, cx);
18488    }
18489
18490    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18491        if let Some(show_line_numbers) = self.show_line_numbers {
18492            return show_line_numbers;
18493        }
18494        EditorSettings::get_global(cx).gutter.line_numbers
18495    }
18496
18497    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18498        self.use_relative_line_numbers
18499            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18500    }
18501
18502    pub fn toggle_relative_line_numbers(
18503        &mut self,
18504        _: &ToggleRelativeLineNumbers,
18505        _: &mut Window,
18506        cx: &mut Context<Self>,
18507    ) {
18508        let is_relative = self.should_use_relative_line_numbers(cx);
18509        self.set_relative_line_number(Some(!is_relative), cx)
18510    }
18511
18512    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18513        self.use_relative_line_numbers = is_relative;
18514        cx.notify();
18515    }
18516
18517    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18518        self.show_gutter = show_gutter;
18519        cx.notify();
18520    }
18521
18522    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18523        self.show_scrollbars = ScrollbarAxes {
18524            horizontal: show,
18525            vertical: show,
18526        };
18527        cx.notify();
18528    }
18529
18530    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18531        self.show_scrollbars.vertical = show;
18532        cx.notify();
18533    }
18534
18535    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18536        self.show_scrollbars.horizontal = show;
18537        cx.notify();
18538    }
18539
18540    pub fn set_minimap_visibility(
18541        &mut self,
18542        minimap_visibility: MinimapVisibility,
18543        window: &mut Window,
18544        cx: &mut Context<Self>,
18545    ) {
18546        if self.minimap_visibility != minimap_visibility {
18547            if minimap_visibility.visible() && self.minimap.is_none() {
18548                let minimap_settings = EditorSettings::get_global(cx).minimap;
18549                self.minimap =
18550                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18551            }
18552            self.minimap_visibility = minimap_visibility;
18553            cx.notify();
18554        }
18555    }
18556
18557    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18558        self.set_show_scrollbars(false, cx);
18559        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18560    }
18561
18562    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18563        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18564    }
18565
18566    /// Normally the text in full mode and auto height editors is padded on the
18567    /// left side by roughly half a character width for improved hit testing.
18568    ///
18569    /// Use this method to disable this for cases where this is not wanted (e.g.
18570    /// if you want to align the editor text with some other text above or below)
18571    /// or if you want to add this padding to single-line editors.
18572    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18573        self.offset_content = offset_content;
18574        cx.notify();
18575    }
18576
18577    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18578        self.show_line_numbers = Some(show_line_numbers);
18579        cx.notify();
18580    }
18581
18582    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18583        self.disable_expand_excerpt_buttons = true;
18584        cx.notify();
18585    }
18586
18587    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18588        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18589        cx.notify();
18590    }
18591
18592    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18593        self.show_code_actions = Some(show_code_actions);
18594        cx.notify();
18595    }
18596
18597    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18598        self.show_runnables = Some(show_runnables);
18599        cx.notify();
18600    }
18601
18602    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18603        self.show_breakpoints = Some(show_breakpoints);
18604        cx.notify();
18605    }
18606
18607    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18608        if self.display_map.read(cx).masked != masked {
18609            self.display_map.update(cx, |map, _| map.masked = masked);
18610        }
18611        cx.notify()
18612    }
18613
18614    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18615        self.show_wrap_guides = Some(show_wrap_guides);
18616        cx.notify();
18617    }
18618
18619    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18620        self.show_indent_guides = Some(show_indent_guides);
18621        cx.notify();
18622    }
18623
18624    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18625        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18626            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
18627                if let Some(dir) = file.abs_path(cx).parent() {
18628                    return Some(dir.to_owned());
18629                }
18630            }
18631
18632            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18633                return Some(project_path.path.to_path_buf());
18634            }
18635        }
18636
18637        None
18638    }
18639
18640    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18641        self.active_excerpt(cx)?
18642            .1
18643            .read(cx)
18644            .file()
18645            .and_then(|f| f.as_local())
18646    }
18647
18648    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18649        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18650            let buffer = buffer.read(cx);
18651            if let Some(project_path) = buffer.project_path(cx) {
18652                let project = self.project.as_ref()?.read(cx);
18653                project.absolute_path(&project_path, cx)
18654            } else {
18655                buffer
18656                    .file()
18657                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18658            }
18659        })
18660    }
18661
18662    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18663        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18664            let project_path = buffer.read(cx).project_path(cx)?;
18665            let project = self.project.as_ref()?.read(cx);
18666            let entry = project.entry_for_path(&project_path, cx)?;
18667            let path = entry.path.to_path_buf();
18668            Some(path)
18669        })
18670    }
18671
18672    pub fn reveal_in_finder(
18673        &mut self,
18674        _: &RevealInFileManager,
18675        _window: &mut Window,
18676        cx: &mut Context<Self>,
18677    ) {
18678        if let Some(target) = self.target_file(cx) {
18679            cx.reveal_path(&target.abs_path(cx));
18680        }
18681    }
18682
18683    pub fn copy_path(
18684        &mut self,
18685        _: &zed_actions::workspace::CopyPath,
18686        _window: &mut Window,
18687        cx: &mut Context<Self>,
18688    ) {
18689        if let Some(path) = self.target_file_abs_path(cx) {
18690            if let Some(path) = path.to_str() {
18691                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18692            }
18693        }
18694    }
18695
18696    pub fn copy_relative_path(
18697        &mut self,
18698        _: &zed_actions::workspace::CopyRelativePath,
18699        _window: &mut Window,
18700        cx: &mut Context<Self>,
18701    ) {
18702        if let Some(path) = self.target_file_path(cx) {
18703            if let Some(path) = path.to_str() {
18704                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18705            }
18706        }
18707    }
18708
18709    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18710        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18711            buffer.read(cx).project_path(cx)
18712        } else {
18713            None
18714        }
18715    }
18716
18717    // Returns true if the editor handled a go-to-line request
18718    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18719        maybe!({
18720            let breakpoint_store = self.breakpoint_store.as_ref()?;
18721
18722            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18723            else {
18724                self.clear_row_highlights::<ActiveDebugLine>();
18725                return None;
18726            };
18727
18728            let position = active_stack_frame.position;
18729            let buffer_id = position.buffer_id?;
18730            let snapshot = self
18731                .project
18732                .as_ref()?
18733                .read(cx)
18734                .buffer_for_id(buffer_id, cx)?
18735                .read(cx)
18736                .snapshot();
18737
18738            let mut handled = false;
18739            for (id, ExcerptRange { context, .. }) in
18740                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18741            {
18742                if context.start.cmp(&position, &snapshot).is_ge()
18743                    || context.end.cmp(&position, &snapshot).is_lt()
18744                {
18745                    continue;
18746                }
18747                let snapshot = self.buffer.read(cx).snapshot(cx);
18748                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18749
18750                handled = true;
18751                self.clear_row_highlights::<ActiveDebugLine>();
18752
18753                self.go_to_line::<ActiveDebugLine>(
18754                    multibuffer_anchor,
18755                    Some(cx.theme().colors().editor_debugger_active_line_background),
18756                    window,
18757                    cx,
18758                );
18759
18760                cx.notify();
18761            }
18762
18763            handled.then_some(())
18764        })
18765        .is_some()
18766    }
18767
18768    pub fn copy_file_name_without_extension(
18769        &mut self,
18770        _: &CopyFileNameWithoutExtension,
18771        _: &mut Window,
18772        cx: &mut Context<Self>,
18773    ) {
18774        if let Some(file) = self.target_file(cx) {
18775            if let Some(file_stem) = file.path().file_stem() {
18776                if let Some(name) = file_stem.to_str() {
18777                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18778                }
18779            }
18780        }
18781    }
18782
18783    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18784        if let Some(file) = self.target_file(cx) {
18785            if let Some(file_name) = file.path().file_name() {
18786                if let Some(name) = file_name.to_str() {
18787                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18788                }
18789            }
18790        }
18791    }
18792
18793    pub fn toggle_git_blame(
18794        &mut self,
18795        _: &::git::Blame,
18796        window: &mut Window,
18797        cx: &mut Context<Self>,
18798    ) {
18799        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18800
18801        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18802            self.start_git_blame(true, window, cx);
18803        }
18804
18805        cx.notify();
18806    }
18807
18808    pub fn toggle_git_blame_inline(
18809        &mut self,
18810        _: &ToggleGitBlameInline,
18811        window: &mut Window,
18812        cx: &mut Context<Self>,
18813    ) {
18814        self.toggle_git_blame_inline_internal(true, window, cx);
18815        cx.notify();
18816    }
18817
18818    pub fn open_git_blame_commit(
18819        &mut self,
18820        _: &OpenGitBlameCommit,
18821        window: &mut Window,
18822        cx: &mut Context<Self>,
18823    ) {
18824        self.open_git_blame_commit_internal(window, cx);
18825    }
18826
18827    fn open_git_blame_commit_internal(
18828        &mut self,
18829        window: &mut Window,
18830        cx: &mut Context<Self>,
18831    ) -> Option<()> {
18832        let blame = self.blame.as_ref()?;
18833        let snapshot = self.snapshot(window, cx);
18834        let cursor = self.selections.newest::<Point>(cx).head();
18835        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18836        let blame_entry = blame
18837            .update(cx, |blame, cx| {
18838                blame
18839                    .blame_for_rows(
18840                        &[RowInfo {
18841                            buffer_id: Some(buffer.remote_id()),
18842                            buffer_row: Some(point.row),
18843                            ..Default::default()
18844                        }],
18845                        cx,
18846                    )
18847                    .next()
18848            })
18849            .flatten()?;
18850        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18851        let repo = blame.read(cx).repository(cx)?;
18852        let workspace = self.workspace()?.downgrade();
18853        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18854        None
18855    }
18856
18857    pub fn git_blame_inline_enabled(&self) -> bool {
18858        self.git_blame_inline_enabled
18859    }
18860
18861    pub fn toggle_selection_menu(
18862        &mut self,
18863        _: &ToggleSelectionMenu,
18864        _: &mut Window,
18865        cx: &mut Context<Self>,
18866    ) {
18867        self.show_selection_menu = self
18868            .show_selection_menu
18869            .map(|show_selections_menu| !show_selections_menu)
18870            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18871
18872        cx.notify();
18873    }
18874
18875    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18876        self.show_selection_menu
18877            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18878    }
18879
18880    fn start_git_blame(
18881        &mut self,
18882        user_triggered: bool,
18883        window: &mut Window,
18884        cx: &mut Context<Self>,
18885    ) {
18886        if let Some(project) = self.project.as_ref() {
18887            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18888                return;
18889            };
18890
18891            if buffer.read(cx).file().is_none() {
18892                return;
18893            }
18894
18895            let focused = self.focus_handle(cx).contains_focused(window, cx);
18896
18897            let project = project.clone();
18898            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18899            self.blame_subscription =
18900                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18901            self.blame = Some(blame);
18902        }
18903    }
18904
18905    fn toggle_git_blame_inline_internal(
18906        &mut self,
18907        user_triggered: bool,
18908        window: &mut Window,
18909        cx: &mut Context<Self>,
18910    ) {
18911        if self.git_blame_inline_enabled {
18912            self.git_blame_inline_enabled = false;
18913            self.show_git_blame_inline = false;
18914            self.show_git_blame_inline_delay_task.take();
18915        } else {
18916            self.git_blame_inline_enabled = true;
18917            self.start_git_blame_inline(user_triggered, window, cx);
18918        }
18919
18920        cx.notify();
18921    }
18922
18923    fn start_git_blame_inline(
18924        &mut self,
18925        user_triggered: bool,
18926        window: &mut Window,
18927        cx: &mut Context<Self>,
18928    ) {
18929        self.start_git_blame(user_triggered, window, cx);
18930
18931        if ProjectSettings::get_global(cx)
18932            .git
18933            .inline_blame_delay()
18934            .is_some()
18935        {
18936            self.start_inline_blame_timer(window, cx);
18937        } else {
18938            self.show_git_blame_inline = true
18939        }
18940    }
18941
18942    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18943        self.blame.as_ref()
18944    }
18945
18946    pub fn show_git_blame_gutter(&self) -> bool {
18947        self.show_git_blame_gutter
18948    }
18949
18950    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18951        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18952    }
18953
18954    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18955        self.show_git_blame_inline
18956            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18957            && !self.newest_selection_head_on_empty_line(cx)
18958            && self.has_blame_entries(cx)
18959    }
18960
18961    fn has_blame_entries(&self, cx: &App) -> bool {
18962        self.blame()
18963            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18964    }
18965
18966    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18967        let cursor_anchor = self.selections.newest_anchor().head();
18968
18969        let snapshot = self.buffer.read(cx).snapshot(cx);
18970        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18971
18972        snapshot.line_len(buffer_row) == 0
18973    }
18974
18975    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18976        let buffer_and_selection = maybe!({
18977            let selection = self.selections.newest::<Point>(cx);
18978            let selection_range = selection.range();
18979
18980            let multi_buffer = self.buffer().read(cx);
18981            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18982            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18983
18984            let (buffer, range, _) = if selection.reversed {
18985                buffer_ranges.first()
18986            } else {
18987                buffer_ranges.last()
18988            }?;
18989
18990            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18991                ..text::ToPoint::to_point(&range.end, &buffer).row;
18992            Some((
18993                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18994                selection,
18995            ))
18996        });
18997
18998        let Some((buffer, selection)) = buffer_and_selection else {
18999            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19000        };
19001
19002        let Some(project) = self.project.as_ref() else {
19003            return Task::ready(Err(anyhow!("editor does not have project")));
19004        };
19005
19006        project.update(cx, |project, cx| {
19007            project.get_permalink_to_line(&buffer, selection, cx)
19008        })
19009    }
19010
19011    pub fn copy_permalink_to_line(
19012        &mut self,
19013        _: &CopyPermalinkToLine,
19014        window: &mut Window,
19015        cx: &mut Context<Self>,
19016    ) {
19017        let permalink_task = self.get_permalink_to_line(cx);
19018        let workspace = self.workspace();
19019
19020        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19021            Ok(permalink) => {
19022                cx.update(|_, cx| {
19023                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19024                })
19025                .ok();
19026            }
19027            Err(err) => {
19028                let message = format!("Failed to copy permalink: {err}");
19029
19030                anyhow::Result::<()>::Err(err).log_err();
19031
19032                if let Some(workspace) = workspace {
19033                    workspace
19034                        .update_in(cx, |workspace, _, cx| {
19035                            struct CopyPermalinkToLine;
19036
19037                            workspace.show_toast(
19038                                Toast::new(
19039                                    NotificationId::unique::<CopyPermalinkToLine>(),
19040                                    message,
19041                                ),
19042                                cx,
19043                            )
19044                        })
19045                        .ok();
19046                }
19047            }
19048        })
19049        .detach();
19050    }
19051
19052    pub fn copy_file_location(
19053        &mut self,
19054        _: &CopyFileLocation,
19055        _: &mut Window,
19056        cx: &mut Context<Self>,
19057    ) {
19058        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19059        if let Some(file) = self.target_file(cx) {
19060            if let Some(path) = file.path().to_str() {
19061                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19062            }
19063        }
19064    }
19065
19066    pub fn open_permalink_to_line(
19067        &mut self,
19068        _: &OpenPermalinkToLine,
19069        window: &mut Window,
19070        cx: &mut Context<Self>,
19071    ) {
19072        let permalink_task = self.get_permalink_to_line(cx);
19073        let workspace = self.workspace();
19074
19075        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19076            Ok(permalink) => {
19077                cx.update(|_, cx| {
19078                    cx.open_url(permalink.as_ref());
19079                })
19080                .ok();
19081            }
19082            Err(err) => {
19083                let message = format!("Failed to open permalink: {err}");
19084
19085                anyhow::Result::<()>::Err(err).log_err();
19086
19087                if let Some(workspace) = workspace {
19088                    workspace
19089                        .update(cx, |workspace, cx| {
19090                            struct OpenPermalinkToLine;
19091
19092                            workspace.show_toast(
19093                                Toast::new(
19094                                    NotificationId::unique::<OpenPermalinkToLine>(),
19095                                    message,
19096                                ),
19097                                cx,
19098                            )
19099                        })
19100                        .ok();
19101                }
19102            }
19103        })
19104        .detach();
19105    }
19106
19107    pub fn insert_uuid_v4(
19108        &mut self,
19109        _: &InsertUuidV4,
19110        window: &mut Window,
19111        cx: &mut Context<Self>,
19112    ) {
19113        self.insert_uuid(UuidVersion::V4, window, cx);
19114    }
19115
19116    pub fn insert_uuid_v7(
19117        &mut self,
19118        _: &InsertUuidV7,
19119        window: &mut Window,
19120        cx: &mut Context<Self>,
19121    ) {
19122        self.insert_uuid(UuidVersion::V7, window, cx);
19123    }
19124
19125    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19126        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19127        self.transact(window, cx, |this, window, cx| {
19128            let edits = this
19129                .selections
19130                .all::<Point>(cx)
19131                .into_iter()
19132                .map(|selection| {
19133                    let uuid = match version {
19134                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19135                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19136                    };
19137
19138                    (selection.range(), uuid.to_string())
19139                });
19140            this.edit(edits, cx);
19141            this.refresh_edit_prediction(true, false, window, cx);
19142        });
19143    }
19144
19145    pub fn open_selections_in_multibuffer(
19146        &mut self,
19147        _: &OpenSelectionsInMultibuffer,
19148        window: &mut Window,
19149        cx: &mut Context<Self>,
19150    ) {
19151        let multibuffer = self.buffer.read(cx);
19152
19153        let Some(buffer) = multibuffer.as_singleton() else {
19154            return;
19155        };
19156
19157        let Some(workspace) = self.workspace() else {
19158            return;
19159        };
19160
19161        let title = multibuffer.title(cx).to_string();
19162
19163        let locations = self
19164            .selections
19165            .all_anchors(cx)
19166            .into_iter()
19167            .map(|selection| Location {
19168                buffer: buffer.clone(),
19169                range: selection.start.text_anchor..selection.end.text_anchor,
19170            })
19171            .collect::<Vec<_>>();
19172
19173        cx.spawn_in(window, async move |_, cx| {
19174            workspace.update_in(cx, |workspace, window, cx| {
19175                Self::open_locations_in_multibuffer(
19176                    workspace,
19177                    locations,
19178                    format!("Selections for '{title}'"),
19179                    false,
19180                    MultibufferSelectionMode::All,
19181                    window,
19182                    cx,
19183                );
19184            })
19185        })
19186        .detach();
19187    }
19188
19189    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19190    /// last highlight added will be used.
19191    ///
19192    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19193    pub fn highlight_rows<T: 'static>(
19194        &mut self,
19195        range: Range<Anchor>,
19196        color: Hsla,
19197        options: RowHighlightOptions,
19198        cx: &mut Context<Self>,
19199    ) {
19200        let snapshot = self.buffer().read(cx).snapshot(cx);
19201        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19202        let ix = row_highlights.binary_search_by(|highlight| {
19203            Ordering::Equal
19204                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19205                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19206        });
19207
19208        if let Err(mut ix) = ix {
19209            let index = post_inc(&mut self.highlight_order);
19210
19211            // If this range intersects with the preceding highlight, then merge it with
19212            // the preceding highlight. Otherwise insert a new highlight.
19213            let mut merged = false;
19214            if ix > 0 {
19215                let prev_highlight = &mut row_highlights[ix - 1];
19216                if prev_highlight
19217                    .range
19218                    .end
19219                    .cmp(&range.start, &snapshot)
19220                    .is_ge()
19221                {
19222                    ix -= 1;
19223                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19224                        prev_highlight.range.end = range.end;
19225                    }
19226                    merged = true;
19227                    prev_highlight.index = index;
19228                    prev_highlight.color = color;
19229                    prev_highlight.options = options;
19230                }
19231            }
19232
19233            if !merged {
19234                row_highlights.insert(
19235                    ix,
19236                    RowHighlight {
19237                        range: range.clone(),
19238                        index,
19239                        color,
19240                        options,
19241                        type_id: TypeId::of::<T>(),
19242                    },
19243                );
19244            }
19245
19246            // If any of the following highlights intersect with this one, merge them.
19247            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19248                let highlight = &row_highlights[ix];
19249                if next_highlight
19250                    .range
19251                    .start
19252                    .cmp(&highlight.range.end, &snapshot)
19253                    .is_le()
19254                {
19255                    if next_highlight
19256                        .range
19257                        .end
19258                        .cmp(&highlight.range.end, &snapshot)
19259                        .is_gt()
19260                    {
19261                        row_highlights[ix].range.end = next_highlight.range.end;
19262                    }
19263                    row_highlights.remove(ix + 1);
19264                } else {
19265                    break;
19266                }
19267            }
19268        }
19269    }
19270
19271    /// Remove any highlighted row ranges of the given type that intersect the
19272    /// given ranges.
19273    pub fn remove_highlighted_rows<T: 'static>(
19274        &mut self,
19275        ranges_to_remove: Vec<Range<Anchor>>,
19276        cx: &mut Context<Self>,
19277    ) {
19278        let snapshot = self.buffer().read(cx).snapshot(cx);
19279        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19280        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19281        row_highlights.retain(|highlight| {
19282            while let Some(range_to_remove) = ranges_to_remove.peek() {
19283                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19284                    Ordering::Less | Ordering::Equal => {
19285                        ranges_to_remove.next();
19286                    }
19287                    Ordering::Greater => {
19288                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19289                            Ordering::Less | Ordering::Equal => {
19290                                return false;
19291                            }
19292                            Ordering::Greater => break,
19293                        }
19294                    }
19295                }
19296            }
19297
19298            true
19299        })
19300    }
19301
19302    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19303    pub fn clear_row_highlights<T: 'static>(&mut self) {
19304        self.highlighted_rows.remove(&TypeId::of::<T>());
19305    }
19306
19307    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19308    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19309        self.highlighted_rows
19310            .get(&TypeId::of::<T>())
19311            .map_or(&[] as &[_], |vec| vec.as_slice())
19312            .iter()
19313            .map(|highlight| (highlight.range.clone(), highlight.color))
19314    }
19315
19316    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19317    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19318    /// Allows to ignore certain kinds of highlights.
19319    pub fn highlighted_display_rows(
19320        &self,
19321        window: &mut Window,
19322        cx: &mut App,
19323    ) -> BTreeMap<DisplayRow, LineHighlight> {
19324        let snapshot = self.snapshot(window, cx);
19325        let mut used_highlight_orders = HashMap::default();
19326        self.highlighted_rows
19327            .iter()
19328            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19329            .fold(
19330                BTreeMap::<DisplayRow, LineHighlight>::new(),
19331                |mut unique_rows, highlight| {
19332                    let start = highlight.range.start.to_display_point(&snapshot);
19333                    let end = highlight.range.end.to_display_point(&snapshot);
19334                    let start_row = start.row().0;
19335                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19336                        && end.column() == 0
19337                    {
19338                        end.row().0.saturating_sub(1)
19339                    } else {
19340                        end.row().0
19341                    };
19342                    for row in start_row..=end_row {
19343                        let used_index =
19344                            used_highlight_orders.entry(row).or_insert(highlight.index);
19345                        if highlight.index >= *used_index {
19346                            *used_index = highlight.index;
19347                            unique_rows.insert(
19348                                DisplayRow(row),
19349                                LineHighlight {
19350                                    include_gutter: highlight.options.include_gutter,
19351                                    border: None,
19352                                    background: highlight.color.into(),
19353                                    type_id: Some(highlight.type_id),
19354                                },
19355                            );
19356                        }
19357                    }
19358                    unique_rows
19359                },
19360            )
19361    }
19362
19363    pub fn highlighted_display_row_for_autoscroll(
19364        &self,
19365        snapshot: &DisplaySnapshot,
19366    ) -> Option<DisplayRow> {
19367        self.highlighted_rows
19368            .values()
19369            .flat_map(|highlighted_rows| highlighted_rows.iter())
19370            .filter_map(|highlight| {
19371                if highlight.options.autoscroll {
19372                    Some(highlight.range.start.to_display_point(snapshot).row())
19373                } else {
19374                    None
19375                }
19376            })
19377            .min()
19378    }
19379
19380    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19381        self.highlight_background::<SearchWithinRange>(
19382            ranges,
19383            |colors| colors.colors().editor_document_highlight_read_background,
19384            cx,
19385        )
19386    }
19387
19388    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19389        self.breadcrumb_header = Some(new_header);
19390    }
19391
19392    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19393        self.clear_background_highlights::<SearchWithinRange>(cx);
19394    }
19395
19396    pub fn highlight_background<T: 'static>(
19397        &mut self,
19398        ranges: &[Range<Anchor>],
19399        color_fetcher: fn(&Theme) -> Hsla,
19400        cx: &mut Context<Self>,
19401    ) {
19402        self.background_highlights.insert(
19403            HighlightKey::Type(TypeId::of::<T>()),
19404            (color_fetcher, Arc::from(ranges)),
19405        );
19406        self.scrollbar_marker_state.dirty = true;
19407        cx.notify();
19408    }
19409
19410    pub fn highlight_background_key<T: 'static>(
19411        &mut self,
19412        key: usize,
19413        ranges: &[Range<Anchor>],
19414        color_fetcher: fn(&Theme) -> Hsla,
19415        cx: &mut Context<Self>,
19416    ) {
19417        self.background_highlights.insert(
19418            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19419            (color_fetcher, Arc::from(ranges)),
19420        );
19421        self.scrollbar_marker_state.dirty = true;
19422        cx.notify();
19423    }
19424
19425    pub fn clear_background_highlights<T: 'static>(
19426        &mut self,
19427        cx: &mut Context<Self>,
19428    ) -> Option<BackgroundHighlight> {
19429        let text_highlights = self
19430            .background_highlights
19431            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19432        if !text_highlights.1.is_empty() {
19433            self.scrollbar_marker_state.dirty = true;
19434            cx.notify();
19435        }
19436        Some(text_highlights)
19437    }
19438
19439    pub fn highlight_gutter<T: 'static>(
19440        &mut self,
19441        ranges: impl Into<Vec<Range<Anchor>>>,
19442        color_fetcher: fn(&App) -> Hsla,
19443        cx: &mut Context<Self>,
19444    ) {
19445        self.gutter_highlights
19446            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19447        cx.notify();
19448    }
19449
19450    pub fn clear_gutter_highlights<T: 'static>(
19451        &mut self,
19452        cx: &mut Context<Self>,
19453    ) -> Option<GutterHighlight> {
19454        cx.notify();
19455        self.gutter_highlights.remove(&TypeId::of::<T>())
19456    }
19457
19458    pub fn insert_gutter_highlight<T: 'static>(
19459        &mut self,
19460        range: Range<Anchor>,
19461        color_fetcher: fn(&App) -> Hsla,
19462        cx: &mut Context<Self>,
19463    ) {
19464        let snapshot = self.buffer().read(cx).snapshot(cx);
19465        let mut highlights = self
19466            .gutter_highlights
19467            .remove(&TypeId::of::<T>())
19468            .map(|(_, highlights)| highlights)
19469            .unwrap_or_default();
19470        let ix = highlights.binary_search_by(|highlight| {
19471            Ordering::Equal
19472                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19473                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19474        });
19475        if let Err(ix) = ix {
19476            highlights.insert(ix, range);
19477        }
19478        self.gutter_highlights
19479            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19480    }
19481
19482    pub fn remove_gutter_highlights<T: 'static>(
19483        &mut self,
19484        ranges_to_remove: Vec<Range<Anchor>>,
19485        cx: &mut Context<Self>,
19486    ) {
19487        let snapshot = self.buffer().read(cx).snapshot(cx);
19488        let Some((color_fetcher, mut gutter_highlights)) =
19489            self.gutter_highlights.remove(&TypeId::of::<T>())
19490        else {
19491            return;
19492        };
19493        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19494        gutter_highlights.retain(|highlight| {
19495            while let Some(range_to_remove) = ranges_to_remove.peek() {
19496                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19497                    Ordering::Less | Ordering::Equal => {
19498                        ranges_to_remove.next();
19499                    }
19500                    Ordering::Greater => {
19501                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19502                            Ordering::Less | Ordering::Equal => {
19503                                return false;
19504                            }
19505                            Ordering::Greater => break,
19506                        }
19507                    }
19508                }
19509            }
19510
19511            true
19512        });
19513        self.gutter_highlights
19514            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19515    }
19516
19517    #[cfg(feature = "test-support")]
19518    pub fn all_text_highlights(
19519        &self,
19520        window: &mut Window,
19521        cx: &mut Context<Self>,
19522    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19523        let snapshot = self.snapshot(window, cx);
19524        self.display_map.update(cx, |display_map, _| {
19525            display_map
19526                .all_text_highlights()
19527                .map(|highlight| {
19528                    let (style, ranges) = highlight.as_ref();
19529                    (
19530                        *style,
19531                        ranges
19532                            .iter()
19533                            .map(|range| range.clone().to_display_points(&snapshot))
19534                            .collect(),
19535                    )
19536                })
19537                .collect()
19538        })
19539    }
19540
19541    #[cfg(feature = "test-support")]
19542    pub fn all_text_background_highlights(
19543        &self,
19544        window: &mut Window,
19545        cx: &mut Context<Self>,
19546    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19547        let snapshot = self.snapshot(window, cx);
19548        let buffer = &snapshot.buffer_snapshot;
19549        let start = buffer.anchor_before(0);
19550        let end = buffer.anchor_after(buffer.len());
19551        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19552    }
19553
19554    #[cfg(feature = "test-support")]
19555    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19556        let snapshot = self.buffer().read(cx).snapshot(cx);
19557
19558        let highlights = self
19559            .background_highlights
19560            .get(&HighlightKey::Type(TypeId::of::<
19561                items::BufferSearchHighlights,
19562            >()));
19563
19564        if let Some((_color, ranges)) = highlights {
19565            ranges
19566                .iter()
19567                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19568                .collect_vec()
19569        } else {
19570            vec![]
19571        }
19572    }
19573
19574    fn document_highlights_for_position<'a>(
19575        &'a self,
19576        position: Anchor,
19577        buffer: &'a MultiBufferSnapshot,
19578    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19579        let read_highlights = self
19580            .background_highlights
19581            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19582            .map(|h| &h.1);
19583        let write_highlights = self
19584            .background_highlights
19585            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19586            .map(|h| &h.1);
19587        let left_position = position.bias_left(buffer);
19588        let right_position = position.bias_right(buffer);
19589        read_highlights
19590            .into_iter()
19591            .chain(write_highlights)
19592            .flat_map(move |ranges| {
19593                let start_ix = match ranges.binary_search_by(|probe| {
19594                    let cmp = probe.end.cmp(&left_position, buffer);
19595                    if cmp.is_ge() {
19596                        Ordering::Greater
19597                    } else {
19598                        Ordering::Less
19599                    }
19600                }) {
19601                    Ok(i) | Err(i) => i,
19602                };
19603
19604                ranges[start_ix..]
19605                    .iter()
19606                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19607            })
19608    }
19609
19610    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19611        self.background_highlights
19612            .get(&HighlightKey::Type(TypeId::of::<T>()))
19613            .map_or(false, |(_, highlights)| !highlights.is_empty())
19614    }
19615
19616    pub fn background_highlights_in_range(
19617        &self,
19618        search_range: Range<Anchor>,
19619        display_snapshot: &DisplaySnapshot,
19620        theme: &Theme,
19621    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19622        let mut results = Vec::new();
19623        for (color_fetcher, ranges) in self.background_highlights.values() {
19624            let color = color_fetcher(theme);
19625            let start_ix = match ranges.binary_search_by(|probe| {
19626                let cmp = probe
19627                    .end
19628                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19629                if cmp.is_gt() {
19630                    Ordering::Greater
19631                } else {
19632                    Ordering::Less
19633                }
19634            }) {
19635                Ok(i) | Err(i) => i,
19636            };
19637            for range in &ranges[start_ix..] {
19638                if range
19639                    .start
19640                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19641                    .is_ge()
19642                {
19643                    break;
19644                }
19645
19646                let start = range.start.to_display_point(display_snapshot);
19647                let end = range.end.to_display_point(display_snapshot);
19648                results.push((start..end, color))
19649            }
19650        }
19651        results
19652    }
19653
19654    pub fn background_highlight_row_ranges<T: 'static>(
19655        &self,
19656        search_range: Range<Anchor>,
19657        display_snapshot: &DisplaySnapshot,
19658        count: usize,
19659    ) -> Vec<RangeInclusive<DisplayPoint>> {
19660        let mut results = Vec::new();
19661        let Some((_, ranges)) = self
19662            .background_highlights
19663            .get(&HighlightKey::Type(TypeId::of::<T>()))
19664        else {
19665            return vec![];
19666        };
19667
19668        let start_ix = match ranges.binary_search_by(|probe| {
19669            let cmp = probe
19670                .end
19671                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19672            if cmp.is_gt() {
19673                Ordering::Greater
19674            } else {
19675                Ordering::Less
19676            }
19677        }) {
19678            Ok(i) | Err(i) => i,
19679        };
19680        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19681            if let (Some(start_display), Some(end_display)) = (start, end) {
19682                results.push(
19683                    start_display.to_display_point(display_snapshot)
19684                        ..=end_display.to_display_point(display_snapshot),
19685                );
19686            }
19687        };
19688        let mut start_row: Option<Point> = None;
19689        let mut end_row: Option<Point> = None;
19690        if ranges.len() > count {
19691            return Vec::new();
19692        }
19693        for range in &ranges[start_ix..] {
19694            if range
19695                .start
19696                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19697                .is_ge()
19698            {
19699                break;
19700            }
19701            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19702            if let Some(current_row) = &end_row {
19703                if end.row == current_row.row {
19704                    continue;
19705                }
19706            }
19707            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19708            if start_row.is_none() {
19709                assert_eq!(end_row, None);
19710                start_row = Some(start);
19711                end_row = Some(end);
19712                continue;
19713            }
19714            if let Some(current_end) = end_row.as_mut() {
19715                if start.row > current_end.row + 1 {
19716                    push_region(start_row, end_row);
19717                    start_row = Some(start);
19718                    end_row = Some(end);
19719                } else {
19720                    // Merge two hunks.
19721                    *current_end = end;
19722                }
19723            } else {
19724                unreachable!();
19725            }
19726        }
19727        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19728        push_region(start_row, end_row);
19729        results
19730    }
19731
19732    pub fn gutter_highlights_in_range(
19733        &self,
19734        search_range: Range<Anchor>,
19735        display_snapshot: &DisplaySnapshot,
19736        cx: &App,
19737    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19738        let mut results = Vec::new();
19739        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19740            let color = color_fetcher(cx);
19741            let start_ix = match ranges.binary_search_by(|probe| {
19742                let cmp = probe
19743                    .end
19744                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19745                if cmp.is_gt() {
19746                    Ordering::Greater
19747                } else {
19748                    Ordering::Less
19749                }
19750            }) {
19751                Ok(i) | Err(i) => i,
19752            };
19753            for range in &ranges[start_ix..] {
19754                if range
19755                    .start
19756                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19757                    .is_ge()
19758                {
19759                    break;
19760                }
19761
19762                let start = range.start.to_display_point(display_snapshot);
19763                let end = range.end.to_display_point(display_snapshot);
19764                results.push((start..end, color))
19765            }
19766        }
19767        results
19768    }
19769
19770    /// Get the text ranges corresponding to the redaction query
19771    pub fn redacted_ranges(
19772        &self,
19773        search_range: Range<Anchor>,
19774        display_snapshot: &DisplaySnapshot,
19775        cx: &App,
19776    ) -> Vec<Range<DisplayPoint>> {
19777        display_snapshot
19778            .buffer_snapshot
19779            .redacted_ranges(search_range, |file| {
19780                if let Some(file) = file {
19781                    file.is_private()
19782                        && EditorSettings::get(
19783                            Some(SettingsLocation {
19784                                worktree_id: file.worktree_id(cx),
19785                                path: file.path().as_ref(),
19786                            }),
19787                            cx,
19788                        )
19789                        .redact_private_values
19790                } else {
19791                    false
19792                }
19793            })
19794            .map(|range| {
19795                range.start.to_display_point(display_snapshot)
19796                    ..range.end.to_display_point(display_snapshot)
19797            })
19798            .collect()
19799    }
19800
19801    pub fn highlight_text_key<T: 'static>(
19802        &mut self,
19803        key: usize,
19804        ranges: Vec<Range<Anchor>>,
19805        style: HighlightStyle,
19806        cx: &mut Context<Self>,
19807    ) {
19808        self.display_map.update(cx, |map, _| {
19809            map.highlight_text(
19810                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19811                ranges,
19812                style,
19813            );
19814        });
19815        cx.notify();
19816    }
19817
19818    pub fn highlight_text<T: 'static>(
19819        &mut self,
19820        ranges: Vec<Range<Anchor>>,
19821        style: HighlightStyle,
19822        cx: &mut Context<Self>,
19823    ) {
19824        self.display_map.update(cx, |map, _| {
19825            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19826        });
19827        cx.notify();
19828    }
19829
19830    pub(crate) fn highlight_inlays<T: 'static>(
19831        &mut self,
19832        highlights: Vec<InlayHighlight>,
19833        style: HighlightStyle,
19834        cx: &mut Context<Self>,
19835    ) {
19836        self.display_map.update(cx, |map, _| {
19837            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19838        });
19839        cx.notify();
19840    }
19841
19842    pub fn text_highlights<'a, T: 'static>(
19843        &'a self,
19844        cx: &'a App,
19845    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19846        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19847    }
19848
19849    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19850        let cleared = self
19851            .display_map
19852            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19853        if cleared {
19854            cx.notify();
19855        }
19856    }
19857
19858    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19859        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19860            && self.focus_handle.is_focused(window)
19861    }
19862
19863    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19864        self.show_cursor_when_unfocused = is_enabled;
19865        cx.notify();
19866    }
19867
19868    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19869        cx.notify();
19870    }
19871
19872    fn on_debug_session_event(
19873        &mut self,
19874        _session: Entity<Session>,
19875        event: &SessionEvent,
19876        cx: &mut Context<Self>,
19877    ) {
19878        match event {
19879            SessionEvent::InvalidateInlineValue => {
19880                self.refresh_inline_values(cx);
19881            }
19882            _ => {}
19883        }
19884    }
19885
19886    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19887        let Some(project) = self.project.clone() else {
19888            return;
19889        };
19890
19891        if !self.inline_value_cache.enabled {
19892            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19893            self.splice_inlays(&inlays, Vec::new(), cx);
19894            return;
19895        }
19896
19897        let current_execution_position = self
19898            .highlighted_rows
19899            .get(&TypeId::of::<ActiveDebugLine>())
19900            .and_then(|lines| lines.last().map(|line| line.range.end));
19901
19902        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19903            let inline_values = editor
19904                .update(cx, |editor, cx| {
19905                    let Some(current_execution_position) = current_execution_position else {
19906                        return Some(Task::ready(Ok(Vec::new())));
19907                    };
19908
19909                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19910                        let snapshot = buffer.snapshot(cx);
19911
19912                        let excerpt = snapshot.excerpt_containing(
19913                            current_execution_position..current_execution_position,
19914                        )?;
19915
19916                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19917                    })?;
19918
19919                    let range =
19920                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19921
19922                    project.inline_values(buffer, range, cx)
19923                })
19924                .ok()
19925                .flatten()?
19926                .await
19927                .context("refreshing debugger inlays")
19928                .log_err()?;
19929
19930            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19931
19932            for (buffer_id, inline_value) in inline_values
19933                .into_iter()
19934                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19935            {
19936                buffer_inline_values
19937                    .entry(buffer_id)
19938                    .or_default()
19939                    .push(inline_value);
19940            }
19941
19942            editor
19943                .update(cx, |editor, cx| {
19944                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19945                    let mut new_inlays = Vec::default();
19946
19947                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19948                        let buffer_id = buffer_snapshot.remote_id();
19949                        buffer_inline_values
19950                            .get(&buffer_id)
19951                            .into_iter()
19952                            .flatten()
19953                            .for_each(|hint| {
19954                                let inlay = Inlay::debugger(
19955                                    post_inc(&mut editor.next_inlay_id),
19956                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19957                                    hint.text(),
19958                                );
19959                                if !inlay.text.chars().contains(&'\n') {
19960                                    new_inlays.push(inlay);
19961                                }
19962                            });
19963                    }
19964
19965                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19966                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19967
19968                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19969                })
19970                .ok()?;
19971            Some(())
19972        });
19973    }
19974
19975    fn on_buffer_event(
19976        &mut self,
19977        multibuffer: &Entity<MultiBuffer>,
19978        event: &multi_buffer::Event,
19979        window: &mut Window,
19980        cx: &mut Context<Self>,
19981    ) {
19982        match event {
19983            multi_buffer::Event::Edited {
19984                singleton_buffer_edited,
19985                edited_buffer,
19986            } => {
19987                self.scrollbar_marker_state.dirty = true;
19988                self.active_indent_guides_state.dirty = true;
19989                self.refresh_active_diagnostics(cx);
19990                self.refresh_code_actions(window, cx);
19991                self.refresh_selected_text_highlights(true, window, cx);
19992                self.refresh_single_line_folds(window, cx);
19993                refresh_matching_bracket_highlights(self, window, cx);
19994                if self.has_active_edit_prediction() {
19995                    self.update_visible_edit_prediction(window, cx);
19996                }
19997                if let Some(project) = self.project.as_ref() {
19998                    if let Some(edited_buffer) = edited_buffer {
19999                        project.update(cx, |project, cx| {
20000                            self.registered_buffers
20001                                .entry(edited_buffer.read(cx).remote_id())
20002                                .or_insert_with(|| {
20003                                    project
20004                                        .register_buffer_with_language_servers(&edited_buffer, cx)
20005                                });
20006                        });
20007                    }
20008                }
20009                cx.emit(EditorEvent::BufferEdited);
20010                cx.emit(SearchEvent::MatchesInvalidated);
20011
20012                if let Some(buffer) = edited_buffer {
20013                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20014                }
20015
20016                if *singleton_buffer_edited {
20017                    if let Some(buffer) = edited_buffer {
20018                        if buffer.read(cx).file().is_none() {
20019                            cx.emit(EditorEvent::TitleChanged);
20020                        }
20021                    }
20022                    if let Some(project) = &self.project {
20023                        #[allow(clippy::mutable_key_type)]
20024                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20025                            multibuffer
20026                                .all_buffers()
20027                                .into_iter()
20028                                .filter_map(|buffer| {
20029                                    buffer.update(cx, |buffer, cx| {
20030                                        let language = buffer.language()?;
20031                                        let should_discard = project.update(cx, |project, cx| {
20032                                            project.is_local()
20033                                                && !project.has_language_servers_for(buffer, cx)
20034                                        });
20035                                        should_discard.not().then_some(language.clone())
20036                                    })
20037                                })
20038                                .collect::<HashSet<_>>()
20039                        });
20040                        if !languages_affected.is_empty() {
20041                            self.refresh_inlay_hints(
20042                                InlayHintRefreshReason::BufferEdited(languages_affected),
20043                                cx,
20044                            );
20045                        }
20046                    }
20047                }
20048
20049                let Some(project) = &self.project else { return };
20050                let (telemetry, is_via_ssh) = {
20051                    let project = project.read(cx);
20052                    let telemetry = project.client().telemetry().clone();
20053                    let is_via_ssh = project.is_via_ssh();
20054                    (telemetry, is_via_ssh)
20055                };
20056                refresh_linked_ranges(self, window, cx);
20057                telemetry.log_edit_event("editor", is_via_ssh);
20058            }
20059            multi_buffer::Event::ExcerptsAdded {
20060                buffer,
20061                predecessor,
20062                excerpts,
20063            } => {
20064                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20065                let buffer_id = buffer.read(cx).remote_id();
20066                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
20067                    if let Some(project) = &self.project {
20068                        update_uncommitted_diff_for_buffer(
20069                            cx.entity(),
20070                            project,
20071                            [buffer.clone()],
20072                            self.buffer.clone(),
20073                            cx,
20074                        )
20075                        .detach();
20076                    }
20077                }
20078                self.update_lsp_data(false, Some(buffer_id), window, cx);
20079                cx.emit(EditorEvent::ExcerptsAdded {
20080                    buffer: buffer.clone(),
20081                    predecessor: *predecessor,
20082                    excerpts: excerpts.clone(),
20083                });
20084                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20085            }
20086            multi_buffer::Event::ExcerptsRemoved {
20087                ids,
20088                removed_buffer_ids,
20089            } => {
20090                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20091                let buffer = self.buffer.read(cx);
20092                self.registered_buffers
20093                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20094                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20095                cx.emit(EditorEvent::ExcerptsRemoved {
20096                    ids: ids.clone(),
20097                    removed_buffer_ids: removed_buffer_ids.clone(),
20098                });
20099            }
20100            multi_buffer::Event::ExcerptsEdited {
20101                excerpt_ids,
20102                buffer_ids,
20103            } => {
20104                self.display_map.update(cx, |map, cx| {
20105                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20106                });
20107                cx.emit(EditorEvent::ExcerptsEdited {
20108                    ids: excerpt_ids.clone(),
20109                });
20110            }
20111            multi_buffer::Event::ExcerptsExpanded { ids } => {
20112                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20113                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20114            }
20115            multi_buffer::Event::Reparsed(buffer_id) => {
20116                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20117                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20118
20119                cx.emit(EditorEvent::Reparsed(*buffer_id));
20120            }
20121            multi_buffer::Event::DiffHunksToggled => {
20122                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20123            }
20124            multi_buffer::Event::LanguageChanged(buffer_id) => {
20125                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20126                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20127                cx.emit(EditorEvent::Reparsed(*buffer_id));
20128                cx.notify();
20129            }
20130            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20131            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20132            multi_buffer::Event::FileHandleChanged
20133            | multi_buffer::Event::Reloaded
20134            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20135            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
20136            multi_buffer::Event::DiagnosticsUpdated => {
20137                self.update_diagnostics_state(window, cx);
20138            }
20139            _ => {}
20140        };
20141    }
20142
20143    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20144        if !self.diagnostics_enabled() {
20145            return;
20146        }
20147        self.refresh_active_diagnostics(cx);
20148        self.refresh_inline_diagnostics(true, window, cx);
20149        self.scrollbar_marker_state.dirty = true;
20150        cx.notify();
20151    }
20152
20153    pub fn start_temporary_diff_override(&mut self) {
20154        self.load_diff_task.take();
20155        self.temporary_diff_override = true;
20156    }
20157
20158    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20159        self.temporary_diff_override = false;
20160        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20161        self.buffer.update(cx, |buffer, cx| {
20162            buffer.set_all_diff_hunks_collapsed(cx);
20163        });
20164
20165        if let Some(project) = self.project.clone() {
20166            self.load_diff_task = Some(
20167                update_uncommitted_diff_for_buffer(
20168                    cx.entity(),
20169                    &project,
20170                    self.buffer.read(cx).all_buffers(),
20171                    self.buffer.clone(),
20172                    cx,
20173                )
20174                .shared(),
20175            );
20176        }
20177    }
20178
20179    fn on_display_map_changed(
20180        &mut self,
20181        _: Entity<DisplayMap>,
20182        _: &mut Window,
20183        cx: &mut Context<Self>,
20184    ) {
20185        cx.notify();
20186    }
20187
20188    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20189        if self.diagnostics_enabled() {
20190            let new_severity = EditorSettings::get_global(cx)
20191                .diagnostics_max_severity
20192                .unwrap_or(DiagnosticSeverity::Hint);
20193            self.set_max_diagnostics_severity(new_severity, cx);
20194        }
20195        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20196        self.update_edit_prediction_settings(cx);
20197        self.refresh_edit_prediction(true, false, window, cx);
20198        self.refresh_inline_values(cx);
20199        self.refresh_inlay_hints(
20200            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20201                self.selections.newest_anchor().head(),
20202                &self.buffer.read(cx).snapshot(cx),
20203                cx,
20204            )),
20205            cx,
20206        );
20207
20208        let old_cursor_shape = self.cursor_shape;
20209
20210        {
20211            let editor_settings = EditorSettings::get_global(cx);
20212            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20213            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20214            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20215            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20216        }
20217
20218        if old_cursor_shape != self.cursor_shape {
20219            cx.emit(EditorEvent::CursorShapeChanged);
20220        }
20221
20222        let project_settings = ProjectSettings::get_global(cx);
20223        self.serialize_dirty_buffers =
20224            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20225
20226        if self.mode.is_full() {
20227            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20228            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20229            if self.show_inline_diagnostics != show_inline_diagnostics {
20230                self.show_inline_diagnostics = show_inline_diagnostics;
20231                self.refresh_inline_diagnostics(false, window, cx);
20232            }
20233
20234            if self.git_blame_inline_enabled != inline_blame_enabled {
20235                self.toggle_git_blame_inline_internal(false, window, cx);
20236            }
20237
20238            let minimap_settings = EditorSettings::get_global(cx).minimap;
20239            if self.minimap_visibility != MinimapVisibility::Disabled {
20240                if self.minimap_visibility.settings_visibility()
20241                    != minimap_settings.minimap_enabled()
20242                {
20243                    self.set_minimap_visibility(
20244                        MinimapVisibility::for_mode(self.mode(), cx),
20245                        window,
20246                        cx,
20247                    );
20248                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20249                    minimap_entity.update(cx, |minimap_editor, cx| {
20250                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20251                    })
20252                }
20253            }
20254        }
20255
20256        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20257            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20258        }) {
20259            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20260                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20261            }
20262            self.refresh_colors(false, None, window, cx);
20263        }
20264
20265        cx.notify();
20266    }
20267
20268    pub fn set_searchable(&mut self, searchable: bool) {
20269        self.searchable = searchable;
20270    }
20271
20272    pub fn searchable(&self) -> bool {
20273        self.searchable
20274    }
20275
20276    fn open_proposed_changes_editor(
20277        &mut self,
20278        _: &OpenProposedChangesEditor,
20279        window: &mut Window,
20280        cx: &mut Context<Self>,
20281    ) {
20282        let Some(workspace) = self.workspace() else {
20283            cx.propagate();
20284            return;
20285        };
20286
20287        let selections = self.selections.all::<usize>(cx);
20288        let multi_buffer = self.buffer.read(cx);
20289        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20290        let mut new_selections_by_buffer = HashMap::default();
20291        for selection in selections {
20292            for (buffer, range, _) in
20293                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20294            {
20295                let mut range = range.to_point(buffer);
20296                range.start.column = 0;
20297                range.end.column = buffer.line_len(range.end.row);
20298                new_selections_by_buffer
20299                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20300                    .or_insert(Vec::new())
20301                    .push(range)
20302            }
20303        }
20304
20305        let proposed_changes_buffers = new_selections_by_buffer
20306            .into_iter()
20307            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20308            .collect::<Vec<_>>();
20309        let proposed_changes_editor = cx.new(|cx| {
20310            ProposedChangesEditor::new(
20311                "Proposed changes",
20312                proposed_changes_buffers,
20313                self.project.clone(),
20314                window,
20315                cx,
20316            )
20317        });
20318
20319        window.defer(cx, move |window, cx| {
20320            workspace.update(cx, |workspace, cx| {
20321                workspace.active_pane().update(cx, |pane, cx| {
20322                    pane.add_item(
20323                        Box::new(proposed_changes_editor),
20324                        true,
20325                        true,
20326                        None,
20327                        window,
20328                        cx,
20329                    );
20330                });
20331            });
20332        });
20333    }
20334
20335    pub fn open_excerpts_in_split(
20336        &mut self,
20337        _: &OpenExcerptsSplit,
20338        window: &mut Window,
20339        cx: &mut Context<Self>,
20340    ) {
20341        self.open_excerpts_common(None, true, window, cx)
20342    }
20343
20344    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20345        self.open_excerpts_common(None, false, window, cx)
20346    }
20347
20348    fn open_excerpts_common(
20349        &mut self,
20350        jump_data: Option<JumpData>,
20351        split: bool,
20352        window: &mut Window,
20353        cx: &mut Context<Self>,
20354    ) {
20355        let Some(workspace) = self.workspace() else {
20356            cx.propagate();
20357            return;
20358        };
20359
20360        if self.buffer.read(cx).is_singleton() {
20361            cx.propagate();
20362            return;
20363        }
20364
20365        let mut new_selections_by_buffer = HashMap::default();
20366        match &jump_data {
20367            Some(JumpData::MultiBufferPoint {
20368                excerpt_id,
20369                position,
20370                anchor,
20371                line_offset_from_top,
20372            }) => {
20373                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20374                if let Some(buffer) = multi_buffer_snapshot
20375                    .buffer_id_for_excerpt(*excerpt_id)
20376                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20377                {
20378                    let buffer_snapshot = buffer.read(cx).snapshot();
20379                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20380                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20381                    } else {
20382                        buffer_snapshot.clip_point(*position, Bias::Left)
20383                    };
20384                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20385                    new_selections_by_buffer.insert(
20386                        buffer,
20387                        (
20388                            vec![jump_to_offset..jump_to_offset],
20389                            Some(*line_offset_from_top),
20390                        ),
20391                    );
20392                }
20393            }
20394            Some(JumpData::MultiBufferRow {
20395                row,
20396                line_offset_from_top,
20397            }) => {
20398                let point = MultiBufferPoint::new(row.0, 0);
20399                if let Some((buffer, buffer_point, _)) =
20400                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20401                {
20402                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20403                    new_selections_by_buffer
20404                        .entry(buffer)
20405                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20406                        .0
20407                        .push(buffer_offset..buffer_offset)
20408                }
20409            }
20410            None => {
20411                let selections = self.selections.all::<usize>(cx);
20412                let multi_buffer = self.buffer.read(cx);
20413                for selection in selections {
20414                    for (snapshot, range, _, anchor) in multi_buffer
20415                        .snapshot(cx)
20416                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20417                    {
20418                        if let Some(anchor) = anchor {
20419                            // selection is in a deleted hunk
20420                            let Some(buffer_id) = anchor.buffer_id else {
20421                                continue;
20422                            };
20423                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
20424                                continue;
20425                            };
20426                            let offset = text::ToOffset::to_offset(
20427                                &anchor.text_anchor,
20428                                &buffer_handle.read(cx).snapshot(),
20429                            );
20430                            let range = offset..offset;
20431                            new_selections_by_buffer
20432                                .entry(buffer_handle)
20433                                .or_insert((Vec::new(), None))
20434                                .0
20435                                .push(range)
20436                        } else {
20437                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20438                            else {
20439                                continue;
20440                            };
20441                            new_selections_by_buffer
20442                                .entry(buffer_handle)
20443                                .or_insert((Vec::new(), None))
20444                                .0
20445                                .push(range)
20446                        }
20447                    }
20448                }
20449            }
20450        }
20451
20452        new_selections_by_buffer
20453            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20454
20455        if new_selections_by_buffer.is_empty() {
20456            return;
20457        }
20458
20459        // We defer the pane interaction because we ourselves are a workspace item
20460        // and activating a new item causes the pane to call a method on us reentrantly,
20461        // which panics if we're on the stack.
20462        window.defer(cx, move |window, cx| {
20463            workspace.update(cx, |workspace, cx| {
20464                let pane = if split {
20465                    workspace.adjacent_pane(window, cx)
20466                } else {
20467                    workspace.active_pane().clone()
20468                };
20469
20470                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20471                    let editor = buffer
20472                        .read(cx)
20473                        .file()
20474                        .is_none()
20475                        .then(|| {
20476                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20477                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20478                            // Instead, we try to activate the existing editor in the pane first.
20479                            let (editor, pane_item_index) =
20480                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20481                                    let editor = item.downcast::<Editor>()?;
20482                                    let singleton_buffer =
20483                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20484                                    if singleton_buffer == buffer {
20485                                        Some((editor, i))
20486                                    } else {
20487                                        None
20488                                    }
20489                                })?;
20490                            pane.update(cx, |pane, cx| {
20491                                pane.activate_item(pane_item_index, true, true, window, cx)
20492                            });
20493                            Some(editor)
20494                        })
20495                        .flatten()
20496                        .unwrap_or_else(|| {
20497                            workspace.open_project_item::<Self>(
20498                                pane.clone(),
20499                                buffer,
20500                                true,
20501                                true,
20502                                window,
20503                                cx,
20504                            )
20505                        });
20506
20507                    editor.update(cx, |editor, cx| {
20508                        let autoscroll = match scroll_offset {
20509                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20510                            None => Autoscroll::newest(),
20511                        };
20512                        let nav_history = editor.nav_history.take();
20513                        editor.change_selections(
20514                            SelectionEffects::scroll(autoscroll),
20515                            window,
20516                            cx,
20517                            |s| {
20518                                s.select_ranges(ranges);
20519                            },
20520                        );
20521                        editor.nav_history = nav_history;
20522                    });
20523                }
20524            })
20525        });
20526    }
20527
20528    // For now, don't allow opening excerpts in buffers that aren't backed by
20529    // regular project files.
20530    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20531        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
20532    }
20533
20534    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20535        let snapshot = self.buffer.read(cx).read(cx);
20536        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20537        Some(
20538            ranges
20539                .iter()
20540                .map(move |range| {
20541                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20542                })
20543                .collect(),
20544        )
20545    }
20546
20547    fn selection_replacement_ranges(
20548        &self,
20549        range: Range<OffsetUtf16>,
20550        cx: &mut App,
20551    ) -> Vec<Range<OffsetUtf16>> {
20552        let selections = self.selections.all::<OffsetUtf16>(cx);
20553        let newest_selection = selections
20554            .iter()
20555            .max_by_key(|selection| selection.id)
20556            .unwrap();
20557        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20558        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20559        let snapshot = self.buffer.read(cx).read(cx);
20560        selections
20561            .into_iter()
20562            .map(|mut selection| {
20563                selection.start.0 =
20564                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20565                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20566                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20567                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20568            })
20569            .collect()
20570    }
20571
20572    fn report_editor_event(
20573        &self,
20574        event_type: &'static str,
20575        file_extension: Option<String>,
20576        cx: &App,
20577    ) {
20578        if cfg!(any(test, feature = "test-support")) {
20579            return;
20580        }
20581
20582        let Some(project) = &self.project else { return };
20583
20584        // If None, we are in a file without an extension
20585        let file = self
20586            .buffer
20587            .read(cx)
20588            .as_singleton()
20589            .and_then(|b| b.read(cx).file());
20590        let file_extension = file_extension.or(file
20591            .as_ref()
20592            .and_then(|file| Path::new(file.file_name(cx)).extension())
20593            .and_then(|e| e.to_str())
20594            .map(|a| a.to_string()));
20595
20596        let vim_mode = vim_enabled(cx);
20597
20598        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20599        let copilot_enabled = edit_predictions_provider
20600            == language::language_settings::EditPredictionProvider::Copilot;
20601        let copilot_enabled_for_language = self
20602            .buffer
20603            .read(cx)
20604            .language_settings(cx)
20605            .show_edit_predictions;
20606
20607        let project = project.read(cx);
20608        telemetry::event!(
20609            event_type,
20610            file_extension,
20611            vim_mode,
20612            copilot_enabled,
20613            copilot_enabled_for_language,
20614            edit_predictions_provider,
20615            is_via_ssh = project.is_via_ssh(),
20616        );
20617    }
20618
20619    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20620    /// with each line being an array of {text, highlight} objects.
20621    fn copy_highlight_json(
20622        &mut self,
20623        _: &CopyHighlightJson,
20624        window: &mut Window,
20625        cx: &mut Context<Self>,
20626    ) {
20627        #[derive(Serialize)]
20628        struct Chunk<'a> {
20629            text: String,
20630            highlight: Option<&'a str>,
20631        }
20632
20633        let snapshot = self.buffer.read(cx).snapshot(cx);
20634        let range = self
20635            .selected_text_range(false, window, cx)
20636            .and_then(|selection| {
20637                if selection.range.is_empty() {
20638                    None
20639                } else {
20640                    Some(selection.range)
20641                }
20642            })
20643            .unwrap_or_else(|| 0..snapshot.len());
20644
20645        let chunks = snapshot.chunks(range, true);
20646        let mut lines = Vec::new();
20647        let mut line: VecDeque<Chunk> = VecDeque::new();
20648
20649        let Some(style) = self.style.as_ref() else {
20650            return;
20651        };
20652
20653        for chunk in chunks {
20654            let highlight = chunk
20655                .syntax_highlight_id
20656                .and_then(|id| id.name(&style.syntax));
20657            let mut chunk_lines = chunk.text.split('\n').peekable();
20658            while let Some(text) = chunk_lines.next() {
20659                let mut merged_with_last_token = false;
20660                if let Some(last_token) = line.back_mut() {
20661                    if last_token.highlight == highlight {
20662                        last_token.text.push_str(text);
20663                        merged_with_last_token = true;
20664                    }
20665                }
20666
20667                if !merged_with_last_token {
20668                    line.push_back(Chunk {
20669                        text: text.into(),
20670                        highlight,
20671                    });
20672                }
20673
20674                if chunk_lines.peek().is_some() {
20675                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20676                        line.pop_front();
20677                    }
20678                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20679                        line.pop_back();
20680                    }
20681
20682                    lines.push(mem::take(&mut line));
20683                }
20684            }
20685        }
20686
20687        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20688            return;
20689        };
20690        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20691    }
20692
20693    pub fn open_context_menu(
20694        &mut self,
20695        _: &OpenContextMenu,
20696        window: &mut Window,
20697        cx: &mut Context<Self>,
20698    ) {
20699        self.request_autoscroll(Autoscroll::newest(), cx);
20700        let position = self.selections.newest_display(cx).start;
20701        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20702    }
20703
20704    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20705        &self.inlay_hint_cache
20706    }
20707
20708    pub fn replay_insert_event(
20709        &mut self,
20710        text: &str,
20711        relative_utf16_range: Option<Range<isize>>,
20712        window: &mut Window,
20713        cx: &mut Context<Self>,
20714    ) {
20715        if !self.input_enabled {
20716            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20717            return;
20718        }
20719        if let Some(relative_utf16_range) = relative_utf16_range {
20720            let selections = self.selections.all::<OffsetUtf16>(cx);
20721            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20722                let new_ranges = selections.into_iter().map(|range| {
20723                    let start = OffsetUtf16(
20724                        range
20725                            .head()
20726                            .0
20727                            .saturating_add_signed(relative_utf16_range.start),
20728                    );
20729                    let end = OffsetUtf16(
20730                        range
20731                            .head()
20732                            .0
20733                            .saturating_add_signed(relative_utf16_range.end),
20734                    );
20735                    start..end
20736                });
20737                s.select_ranges(new_ranges);
20738            });
20739        }
20740
20741        self.handle_input(text, window, cx);
20742    }
20743
20744    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20745        let Some(provider) = self.semantics_provider.as_ref() else {
20746            return false;
20747        };
20748
20749        let mut supports = false;
20750        self.buffer().update(cx, |this, cx| {
20751            this.for_each_buffer(|buffer| {
20752                supports |= provider.supports_inlay_hints(buffer, cx);
20753            });
20754        });
20755
20756        supports
20757    }
20758
20759    pub fn is_focused(&self, window: &Window) -> bool {
20760        self.focus_handle.is_focused(window)
20761    }
20762
20763    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20764        cx.emit(EditorEvent::Focused);
20765
20766        if let Some(descendant) = self
20767            .last_focused_descendant
20768            .take()
20769            .and_then(|descendant| descendant.upgrade())
20770        {
20771            window.focus(&descendant);
20772        } else {
20773            if let Some(blame) = self.blame.as_ref() {
20774                blame.update(cx, GitBlame::focus)
20775            }
20776
20777            self.blink_manager.update(cx, BlinkManager::enable);
20778            self.show_cursor_names(window, cx);
20779            self.buffer.update(cx, |buffer, cx| {
20780                buffer.finalize_last_transaction(cx);
20781                if self.leader_id.is_none() {
20782                    buffer.set_active_selections(
20783                        &self.selections.disjoint_anchors(),
20784                        self.selections.line_mode,
20785                        self.cursor_shape,
20786                        cx,
20787                    );
20788                }
20789            });
20790        }
20791    }
20792
20793    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20794        cx.emit(EditorEvent::FocusedIn)
20795    }
20796
20797    fn handle_focus_out(
20798        &mut self,
20799        event: FocusOutEvent,
20800        _window: &mut Window,
20801        cx: &mut Context<Self>,
20802    ) {
20803        if event.blurred != self.focus_handle {
20804            self.last_focused_descendant = Some(event.blurred);
20805        }
20806        self.selection_drag_state = SelectionDragState::None;
20807        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20808    }
20809
20810    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20811        self.blink_manager.update(cx, BlinkManager::disable);
20812        self.buffer
20813            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20814
20815        if let Some(blame) = self.blame.as_ref() {
20816            blame.update(cx, GitBlame::blur)
20817        }
20818        if !self.hover_state.focused(window, cx) {
20819            hide_hover(self, cx);
20820        }
20821        if !self
20822            .context_menu
20823            .borrow()
20824            .as_ref()
20825            .is_some_and(|context_menu| context_menu.focused(window, cx))
20826        {
20827            self.hide_context_menu(window, cx);
20828        }
20829        self.discard_edit_prediction(false, cx);
20830        cx.emit(EditorEvent::Blurred);
20831        cx.notify();
20832    }
20833
20834    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20835        let mut pending: String = window
20836            .pending_input_keystrokes()
20837            .into_iter()
20838            .flatten()
20839            .filter_map(|keystroke| {
20840                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20841                    keystroke.key_char.clone()
20842                } else {
20843                    None
20844                }
20845            })
20846            .collect();
20847
20848        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20849            pending = "".to_string();
20850        }
20851
20852        let existing_pending = self
20853            .text_highlights::<PendingInput>(cx)
20854            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
20855        if existing_pending.is_none() && pending.is_empty() {
20856            return;
20857        }
20858        let transaction =
20859            self.transact(window, cx, |this, window, cx| {
20860                let selections = this.selections.all::<usize>(cx);
20861                let edits = selections
20862                    .iter()
20863                    .map(|selection| (selection.end..selection.end, pending.clone()));
20864                this.edit(edits, cx);
20865                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20866                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20867                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20868                    }));
20869                });
20870                if let Some(existing_ranges) = existing_pending {
20871                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20872                    this.edit(edits, cx);
20873                }
20874            });
20875
20876        let snapshot = self.snapshot(window, cx);
20877        let ranges = self
20878            .selections
20879            .all::<usize>(cx)
20880            .into_iter()
20881            .map(|selection| {
20882                snapshot.buffer_snapshot.anchor_after(selection.end)
20883                    ..snapshot
20884                        .buffer_snapshot
20885                        .anchor_before(selection.end + pending.len())
20886            })
20887            .collect();
20888
20889        if pending.is_empty() {
20890            self.clear_highlights::<PendingInput>(cx);
20891        } else {
20892            self.highlight_text::<PendingInput>(
20893                ranges,
20894                HighlightStyle {
20895                    underline: Some(UnderlineStyle {
20896                        thickness: px(1.),
20897                        color: None,
20898                        wavy: false,
20899                    }),
20900                    ..Default::default()
20901                },
20902                cx,
20903            );
20904        }
20905
20906        self.ime_transaction = self.ime_transaction.or(transaction);
20907        if let Some(transaction) = self.ime_transaction {
20908            self.buffer.update(cx, |buffer, cx| {
20909                buffer.group_until_transaction(transaction, cx);
20910            });
20911        }
20912
20913        if self.text_highlights::<PendingInput>(cx).is_none() {
20914            self.ime_transaction.take();
20915        }
20916    }
20917
20918    pub fn register_action_renderer(
20919        &mut self,
20920        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20921    ) -> Subscription {
20922        let id = self.next_editor_action_id.post_inc();
20923        self.editor_actions
20924            .borrow_mut()
20925            .insert(id, Box::new(listener));
20926
20927        let editor_actions = self.editor_actions.clone();
20928        Subscription::new(move || {
20929            editor_actions.borrow_mut().remove(&id);
20930        })
20931    }
20932
20933    pub fn register_action<A: Action>(
20934        &mut self,
20935        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20936    ) -> Subscription {
20937        let id = self.next_editor_action_id.post_inc();
20938        let listener = Arc::new(listener);
20939        self.editor_actions.borrow_mut().insert(
20940            id,
20941            Box::new(move |_, window, _| {
20942                let listener = listener.clone();
20943                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20944                    let action = action.downcast_ref().unwrap();
20945                    if phase == DispatchPhase::Bubble {
20946                        listener(action, window, cx)
20947                    }
20948                })
20949            }),
20950        );
20951
20952        let editor_actions = self.editor_actions.clone();
20953        Subscription::new(move || {
20954            editor_actions.borrow_mut().remove(&id);
20955        })
20956    }
20957
20958    pub fn file_header_size(&self) -> u32 {
20959        FILE_HEADER_HEIGHT
20960    }
20961
20962    pub fn restore(
20963        &mut self,
20964        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20965        window: &mut Window,
20966        cx: &mut Context<Self>,
20967    ) {
20968        let workspace = self.workspace();
20969        let project = self.project.as_ref();
20970        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20971            let mut tasks = Vec::new();
20972            for (buffer_id, changes) in revert_changes {
20973                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20974                    buffer.update(cx, |buffer, cx| {
20975                        buffer.edit(
20976                            changes
20977                                .into_iter()
20978                                .map(|(range, text)| (range, text.to_string())),
20979                            None,
20980                            cx,
20981                        );
20982                    });
20983
20984                    if let Some(project) =
20985                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20986                    {
20987                        project.update(cx, |project, cx| {
20988                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20989                        })
20990                    }
20991                }
20992            }
20993            tasks
20994        });
20995        cx.spawn_in(window, async move |_, cx| {
20996            for (buffer, task) in save_tasks {
20997                let result = task.await;
20998                if result.is_err() {
20999                    let Some(path) = buffer
21000                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21001                        .ok()
21002                    else {
21003                        continue;
21004                    };
21005                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21006                        let Some(task) = cx
21007                            .update_window_entity(&workspace, |workspace, window, cx| {
21008                                workspace
21009                                    .open_path_preview(path, None, false, false, false, window, cx)
21010                            })
21011                            .ok()
21012                        else {
21013                            continue;
21014                        };
21015                        task.await.log_err();
21016                    }
21017                }
21018            }
21019        })
21020        .detach();
21021        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21022            selections.refresh()
21023        });
21024    }
21025
21026    pub fn to_pixel_point(
21027        &self,
21028        source: multi_buffer::Anchor,
21029        editor_snapshot: &EditorSnapshot,
21030        window: &mut Window,
21031    ) -> Option<gpui::Point<Pixels>> {
21032        let source_point = source.to_display_point(editor_snapshot);
21033        self.display_to_pixel_point(source_point, editor_snapshot, window)
21034    }
21035
21036    pub fn display_to_pixel_point(
21037        &self,
21038        source: DisplayPoint,
21039        editor_snapshot: &EditorSnapshot,
21040        window: &mut Window,
21041    ) -> Option<gpui::Point<Pixels>> {
21042        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21043        let text_layout_details = self.text_layout_details(window);
21044        let scroll_top = text_layout_details
21045            .scroll_anchor
21046            .scroll_position(editor_snapshot)
21047            .y;
21048
21049        if source.row().as_f32() < scroll_top.floor() {
21050            return None;
21051        }
21052        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21053        let source_y = line_height * (source.row().as_f32() - scroll_top);
21054        Some(gpui::Point::new(source_x, source_y))
21055    }
21056
21057    pub fn has_visible_completions_menu(&self) -> bool {
21058        !self.edit_prediction_preview_is_active()
21059            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
21060                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21061            })
21062    }
21063
21064    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21065        if self.mode.is_minimap() {
21066            return;
21067        }
21068        self.addons
21069            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21070    }
21071
21072    pub fn unregister_addon<T: Addon>(&mut self) {
21073        self.addons.remove(&std::any::TypeId::of::<T>());
21074    }
21075
21076    pub fn addon<T: Addon>(&self) -> Option<&T> {
21077        let type_id = std::any::TypeId::of::<T>();
21078        self.addons
21079            .get(&type_id)
21080            .and_then(|item| item.to_any().downcast_ref::<T>())
21081    }
21082
21083    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21084        let type_id = std::any::TypeId::of::<T>();
21085        self.addons
21086            .get_mut(&type_id)
21087            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21088    }
21089
21090    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21091        let text_layout_details = self.text_layout_details(window);
21092        let style = &text_layout_details.editor_style;
21093        let font_id = window.text_system().resolve_font(&style.text.font());
21094        let font_size = style.text.font_size.to_pixels(window.rem_size());
21095        let line_height = style.text.line_height_in_pixels(window.rem_size());
21096        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21097        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21098
21099        CharacterDimensions {
21100            em_width,
21101            em_advance,
21102            line_height,
21103        }
21104    }
21105
21106    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21107        self.load_diff_task.clone()
21108    }
21109
21110    fn read_metadata_from_db(
21111        &mut self,
21112        item_id: u64,
21113        workspace_id: WorkspaceId,
21114        window: &mut Window,
21115        cx: &mut Context<Editor>,
21116    ) {
21117        if self.is_singleton(cx)
21118            && !self.mode.is_minimap()
21119            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21120        {
21121            let buffer_snapshot = OnceCell::new();
21122
21123            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
21124                if !folds.is_empty() {
21125                    let snapshot =
21126                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21127                    self.fold_ranges(
21128                        folds
21129                            .into_iter()
21130                            .map(|(start, end)| {
21131                                snapshot.clip_offset(start, Bias::Left)
21132                                    ..snapshot.clip_offset(end, Bias::Right)
21133                            })
21134                            .collect(),
21135                        false,
21136                        window,
21137                        cx,
21138                    );
21139                }
21140            }
21141
21142            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
21143                if !selections.is_empty() {
21144                    let snapshot =
21145                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21146                    // skip adding the initial selection to selection history
21147                    self.selection_history.mode = SelectionHistoryMode::Skipping;
21148                    self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21149                        s.select_ranges(selections.into_iter().map(|(start, end)| {
21150                            snapshot.clip_offset(start, Bias::Left)
21151                                ..snapshot.clip_offset(end, Bias::Right)
21152                        }));
21153                    });
21154                    self.selection_history.mode = SelectionHistoryMode::Normal;
21155                }
21156            };
21157        }
21158
21159        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21160    }
21161
21162    fn update_lsp_data(
21163        &mut self,
21164        ignore_cache: bool,
21165        for_buffer: Option<BufferId>,
21166        window: &mut Window,
21167        cx: &mut Context<'_, Self>,
21168    ) {
21169        self.pull_diagnostics(for_buffer, window, cx);
21170        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21171    }
21172}
21173
21174fn vim_enabled(cx: &App) -> bool {
21175    cx.global::<SettingsStore>()
21176        .raw_user_settings()
21177        .get("vim_mode")
21178        == Some(&serde_json::Value::Bool(true))
21179}
21180
21181fn process_completion_for_edit(
21182    completion: &Completion,
21183    intent: CompletionIntent,
21184    buffer: &Entity<Buffer>,
21185    cursor_position: &text::Anchor,
21186    cx: &mut Context<Editor>,
21187) -> CompletionEdit {
21188    let buffer = buffer.read(cx);
21189    let buffer_snapshot = buffer.snapshot();
21190    let (snippet, new_text) = if completion.is_snippet() {
21191        // Workaround for typescript language server issues so that methods don't expand within
21192        // strings and functions with type expressions. The previous point is used because the query
21193        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21194        let mut snippet_source = completion.new_text.clone();
21195        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21196        previous_point.column = previous_point.column.saturating_sub(1);
21197        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
21198            if scope.prefers_label_for_snippet_in_completion() {
21199                if let Some(label) = completion.label() {
21200                    if matches!(
21201                        completion.kind(),
21202                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21203                    ) {
21204                        snippet_source = label;
21205                    }
21206                }
21207            }
21208        }
21209        match Snippet::parse(&snippet_source).log_err() {
21210            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21211            None => (None, completion.new_text.clone()),
21212        }
21213    } else {
21214        (None, completion.new_text.clone())
21215    };
21216
21217    let mut range_to_replace = {
21218        let replace_range = &completion.replace_range;
21219        if let CompletionSource::Lsp {
21220            insert_range: Some(insert_range),
21221            ..
21222        } = &completion.source
21223        {
21224            debug_assert_eq!(
21225                insert_range.start, replace_range.start,
21226                "insert_range and replace_range should start at the same position"
21227            );
21228            debug_assert!(
21229                insert_range
21230                    .start
21231                    .cmp(&cursor_position, &buffer_snapshot)
21232                    .is_le(),
21233                "insert_range should start before or at cursor position"
21234            );
21235            debug_assert!(
21236                replace_range
21237                    .start
21238                    .cmp(&cursor_position, &buffer_snapshot)
21239                    .is_le(),
21240                "replace_range should start before or at cursor position"
21241            );
21242
21243            let should_replace = match intent {
21244                CompletionIntent::CompleteWithInsert => false,
21245                CompletionIntent::CompleteWithReplace => true,
21246                CompletionIntent::Complete | CompletionIntent::Compose => {
21247                    let insert_mode =
21248                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21249                            .completions
21250                            .lsp_insert_mode;
21251                    match insert_mode {
21252                        LspInsertMode::Insert => false,
21253                        LspInsertMode::Replace => true,
21254                        LspInsertMode::ReplaceSubsequence => {
21255                            let mut text_to_replace = buffer.chars_for_range(
21256                                buffer.anchor_before(replace_range.start)
21257                                    ..buffer.anchor_after(replace_range.end),
21258                            );
21259                            let mut current_needle = text_to_replace.next();
21260                            for haystack_ch in completion.label.text.chars() {
21261                                if let Some(needle_ch) = current_needle {
21262                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
21263                                        current_needle = text_to_replace.next();
21264                                    }
21265                                }
21266                            }
21267                            current_needle.is_none()
21268                        }
21269                        LspInsertMode::ReplaceSuffix => {
21270                            if replace_range
21271                                .end
21272                                .cmp(&cursor_position, &buffer_snapshot)
21273                                .is_gt()
21274                            {
21275                                let range_after_cursor = *cursor_position..replace_range.end;
21276                                let text_after_cursor = buffer
21277                                    .text_for_range(
21278                                        buffer.anchor_before(range_after_cursor.start)
21279                                            ..buffer.anchor_after(range_after_cursor.end),
21280                                    )
21281                                    .collect::<String>()
21282                                    .to_ascii_lowercase();
21283                                completion
21284                                    .label
21285                                    .text
21286                                    .to_ascii_lowercase()
21287                                    .ends_with(&text_after_cursor)
21288                            } else {
21289                                true
21290                            }
21291                        }
21292                    }
21293                }
21294            };
21295
21296            if should_replace {
21297                replace_range.clone()
21298            } else {
21299                insert_range.clone()
21300            }
21301        } else {
21302            replace_range.clone()
21303        }
21304    };
21305
21306    if range_to_replace
21307        .end
21308        .cmp(&cursor_position, &buffer_snapshot)
21309        .is_lt()
21310    {
21311        range_to_replace.end = *cursor_position;
21312    }
21313
21314    CompletionEdit {
21315        new_text,
21316        replace_range: range_to_replace.to_offset(&buffer),
21317        snippet,
21318    }
21319}
21320
21321struct CompletionEdit {
21322    new_text: String,
21323    replace_range: Range<usize>,
21324    snippet: Option<Snippet>,
21325}
21326
21327fn insert_extra_newline_brackets(
21328    buffer: &MultiBufferSnapshot,
21329    range: Range<usize>,
21330    language: &language::LanguageScope,
21331) -> bool {
21332    let leading_whitespace_len = buffer
21333        .reversed_chars_at(range.start)
21334        .take_while(|c| c.is_whitespace() && *c != '\n')
21335        .map(|c| c.len_utf8())
21336        .sum::<usize>();
21337    let trailing_whitespace_len = buffer
21338        .chars_at(range.end)
21339        .take_while(|c| c.is_whitespace() && *c != '\n')
21340        .map(|c| c.len_utf8())
21341        .sum::<usize>();
21342    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21343
21344    language.brackets().any(|(pair, enabled)| {
21345        let pair_start = pair.start.trim_end();
21346        let pair_end = pair.end.trim_start();
21347
21348        enabled
21349            && pair.newline
21350            && buffer.contains_str_at(range.end, pair_end)
21351            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21352    })
21353}
21354
21355fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21356    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21357        [(buffer, range, _)] => (*buffer, range.clone()),
21358        _ => return false,
21359    };
21360    let pair = {
21361        let mut result: Option<BracketMatch> = None;
21362
21363        for pair in buffer
21364            .all_bracket_ranges(range.clone())
21365            .filter(move |pair| {
21366                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21367            })
21368        {
21369            let len = pair.close_range.end - pair.open_range.start;
21370
21371            if let Some(existing) = &result {
21372                let existing_len = existing.close_range.end - existing.open_range.start;
21373                if len > existing_len {
21374                    continue;
21375                }
21376            }
21377
21378            result = Some(pair);
21379        }
21380
21381        result
21382    };
21383    let Some(pair) = pair else {
21384        return false;
21385    };
21386    pair.newline_only
21387        && buffer
21388            .chars_for_range(pair.open_range.end..range.start)
21389            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21390            .all(|c| c.is_whitespace() && c != '\n')
21391}
21392
21393fn update_uncommitted_diff_for_buffer(
21394    editor: Entity<Editor>,
21395    project: &Entity<Project>,
21396    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21397    buffer: Entity<MultiBuffer>,
21398    cx: &mut App,
21399) -> Task<()> {
21400    let mut tasks = Vec::new();
21401    project.update(cx, |project, cx| {
21402        for buffer in buffers {
21403            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21404                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21405            }
21406        }
21407    });
21408    cx.spawn(async move |cx| {
21409        let diffs = future::join_all(tasks).await;
21410        if editor
21411            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21412            .unwrap_or(false)
21413        {
21414            return;
21415        }
21416
21417        buffer
21418            .update(cx, |buffer, cx| {
21419                for diff in diffs.into_iter().flatten() {
21420                    buffer.add_diff(diff, cx);
21421                }
21422            })
21423            .ok();
21424    })
21425}
21426
21427fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21428    let tab_size = tab_size.get() as usize;
21429    let mut width = offset;
21430
21431    for ch in text.chars() {
21432        width += if ch == '\t' {
21433            tab_size - (width % tab_size)
21434        } else {
21435            1
21436        };
21437    }
21438
21439    width - offset
21440}
21441
21442#[cfg(test)]
21443mod tests {
21444    use super::*;
21445
21446    #[test]
21447    fn test_string_size_with_expanded_tabs() {
21448        let nz = |val| NonZeroU32::new(val).unwrap();
21449        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21450        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21451        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21452        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21453        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21454        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21455        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21456        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21457    }
21458}
21459
21460/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21461struct WordBreakingTokenizer<'a> {
21462    input: &'a str,
21463}
21464
21465impl<'a> WordBreakingTokenizer<'a> {
21466    fn new(input: &'a str) -> Self {
21467        Self { input }
21468    }
21469}
21470
21471fn is_char_ideographic(ch: char) -> bool {
21472    use unicode_script::Script::*;
21473    use unicode_script::UnicodeScript;
21474    matches!(ch.script(), Han | Tangut | Yi)
21475}
21476
21477fn is_grapheme_ideographic(text: &str) -> bool {
21478    text.chars().any(is_char_ideographic)
21479}
21480
21481fn is_grapheme_whitespace(text: &str) -> bool {
21482    text.chars().any(|x| x.is_whitespace())
21483}
21484
21485fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21486    text.chars().next().map_or(false, |ch| {
21487        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
21488    })
21489}
21490
21491#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21492enum WordBreakToken<'a> {
21493    Word { token: &'a str, grapheme_len: usize },
21494    InlineWhitespace { token: &'a str, grapheme_len: usize },
21495    Newline,
21496}
21497
21498impl<'a> Iterator for WordBreakingTokenizer<'a> {
21499    /// Yields a span, the count of graphemes in the token, and whether it was
21500    /// whitespace. Note that it also breaks at word boundaries.
21501    type Item = WordBreakToken<'a>;
21502
21503    fn next(&mut self) -> Option<Self::Item> {
21504        use unicode_segmentation::UnicodeSegmentation;
21505        if self.input.is_empty() {
21506            return None;
21507        }
21508
21509        let mut iter = self.input.graphemes(true).peekable();
21510        let mut offset = 0;
21511        let mut grapheme_len = 0;
21512        if let Some(first_grapheme) = iter.next() {
21513            let is_newline = first_grapheme == "\n";
21514            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21515            offset += first_grapheme.len();
21516            grapheme_len += 1;
21517            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21518                if let Some(grapheme) = iter.peek().copied() {
21519                    if should_stay_with_preceding_ideograph(grapheme) {
21520                        offset += grapheme.len();
21521                        grapheme_len += 1;
21522                    }
21523                }
21524            } else {
21525                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21526                let mut next_word_bound = words.peek().copied();
21527                if next_word_bound.map_or(false, |(i, _)| i == 0) {
21528                    next_word_bound = words.next();
21529                }
21530                while let Some(grapheme) = iter.peek().copied() {
21531                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
21532                        break;
21533                    };
21534                    if is_grapheme_whitespace(grapheme) != is_whitespace
21535                        || (grapheme == "\n") != is_newline
21536                    {
21537                        break;
21538                    };
21539                    offset += grapheme.len();
21540                    grapheme_len += 1;
21541                    iter.next();
21542                }
21543            }
21544            let token = &self.input[..offset];
21545            self.input = &self.input[offset..];
21546            if token == "\n" {
21547                Some(WordBreakToken::Newline)
21548            } else if is_whitespace {
21549                Some(WordBreakToken::InlineWhitespace {
21550                    token,
21551                    grapheme_len,
21552                })
21553            } else {
21554                Some(WordBreakToken::Word {
21555                    token,
21556                    grapheme_len,
21557                })
21558            }
21559        } else {
21560            None
21561        }
21562    }
21563}
21564
21565#[test]
21566fn test_word_breaking_tokenizer() {
21567    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21568        ("", &[]),
21569        ("  ", &[whitespace("  ", 2)]),
21570        ("Ʒ", &[word("Ʒ", 1)]),
21571        ("Ǽ", &[word("Ǽ", 1)]),
21572        ("", &[word("", 1)]),
21573        ("⋑⋑", &[word("⋑⋑", 2)]),
21574        (
21575            "原理,进而",
21576            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21577        ),
21578        (
21579            "hello world",
21580            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21581        ),
21582        (
21583            "hello, world",
21584            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21585        ),
21586        (
21587            "  hello world",
21588            &[
21589                whitespace("  ", 2),
21590                word("hello", 5),
21591                whitespace(" ", 1),
21592                word("world", 5),
21593            ],
21594        ),
21595        (
21596            "这是什么 \n 钢笔",
21597            &[
21598                word("", 1),
21599                word("", 1),
21600                word("", 1),
21601                word("", 1),
21602                whitespace(" ", 1),
21603                newline(),
21604                whitespace(" ", 1),
21605                word("", 1),
21606                word("", 1),
21607            ],
21608        ),
21609        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21610    ];
21611
21612    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21613        WordBreakToken::Word {
21614            token,
21615            grapheme_len,
21616        }
21617    }
21618
21619    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21620        WordBreakToken::InlineWhitespace {
21621            token,
21622            grapheme_len,
21623        }
21624    }
21625
21626    fn newline() -> WordBreakToken<'static> {
21627        WordBreakToken::Newline
21628    }
21629
21630    for (input, result) in tests {
21631        assert_eq!(
21632            WordBreakingTokenizer::new(input)
21633                .collect::<Vec<_>>()
21634                .as_slice(),
21635            *result,
21636        );
21637    }
21638}
21639
21640fn wrap_with_prefix(
21641    first_line_prefix: String,
21642    subsequent_lines_prefix: String,
21643    unwrapped_text: String,
21644    wrap_column: usize,
21645    tab_size: NonZeroU32,
21646    preserve_existing_whitespace: bool,
21647) -> String {
21648    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21649    let subsequent_lines_prefix_len =
21650        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21651    let mut wrapped_text = String::new();
21652    let mut current_line = first_line_prefix.clone();
21653    let mut is_first_line = true;
21654
21655    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21656    let mut current_line_len = first_line_prefix_len;
21657    let mut in_whitespace = false;
21658    for token in tokenizer {
21659        let have_preceding_whitespace = in_whitespace;
21660        match token {
21661            WordBreakToken::Word {
21662                token,
21663                grapheme_len,
21664            } => {
21665                in_whitespace = false;
21666                let current_prefix_len = if is_first_line {
21667                    first_line_prefix_len
21668                } else {
21669                    subsequent_lines_prefix_len
21670                };
21671                if current_line_len + grapheme_len > wrap_column
21672                    && current_line_len != current_prefix_len
21673                {
21674                    wrapped_text.push_str(current_line.trim_end());
21675                    wrapped_text.push('\n');
21676                    is_first_line = false;
21677                    current_line = subsequent_lines_prefix.clone();
21678                    current_line_len = subsequent_lines_prefix_len;
21679                }
21680                current_line.push_str(token);
21681                current_line_len += grapheme_len;
21682            }
21683            WordBreakToken::InlineWhitespace {
21684                mut token,
21685                mut grapheme_len,
21686            } => {
21687                in_whitespace = true;
21688                if have_preceding_whitespace && !preserve_existing_whitespace {
21689                    continue;
21690                }
21691                if !preserve_existing_whitespace {
21692                    token = " ";
21693                    grapheme_len = 1;
21694                }
21695                let current_prefix_len = if is_first_line {
21696                    first_line_prefix_len
21697                } else {
21698                    subsequent_lines_prefix_len
21699                };
21700                if current_line_len + grapheme_len > wrap_column {
21701                    wrapped_text.push_str(current_line.trim_end());
21702                    wrapped_text.push('\n');
21703                    is_first_line = false;
21704                    current_line = subsequent_lines_prefix.clone();
21705                    current_line_len = subsequent_lines_prefix_len;
21706                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21707                    current_line.push_str(token);
21708                    current_line_len += grapheme_len;
21709                }
21710            }
21711            WordBreakToken::Newline => {
21712                in_whitespace = true;
21713                let current_prefix_len = if is_first_line {
21714                    first_line_prefix_len
21715                } else {
21716                    subsequent_lines_prefix_len
21717                };
21718                if preserve_existing_whitespace {
21719                    wrapped_text.push_str(current_line.trim_end());
21720                    wrapped_text.push('\n');
21721                    is_first_line = false;
21722                    current_line = subsequent_lines_prefix.clone();
21723                    current_line_len = subsequent_lines_prefix_len;
21724                } else if have_preceding_whitespace {
21725                    continue;
21726                } else if current_line_len + 1 > wrap_column
21727                    && current_line_len != current_prefix_len
21728                {
21729                    wrapped_text.push_str(current_line.trim_end());
21730                    wrapped_text.push('\n');
21731                    is_first_line = false;
21732                    current_line = subsequent_lines_prefix.clone();
21733                    current_line_len = subsequent_lines_prefix_len;
21734                } else if current_line_len != current_prefix_len {
21735                    current_line.push(' ');
21736                    current_line_len += 1;
21737                }
21738            }
21739        }
21740    }
21741
21742    if !current_line.is_empty() {
21743        wrapped_text.push_str(&current_line);
21744    }
21745    wrapped_text
21746}
21747
21748#[test]
21749fn test_wrap_with_prefix() {
21750    assert_eq!(
21751        wrap_with_prefix(
21752            "# ".to_string(),
21753            "# ".to_string(),
21754            "abcdefg".to_string(),
21755            4,
21756            NonZeroU32::new(4).unwrap(),
21757            false,
21758        ),
21759        "# abcdefg"
21760    );
21761    assert_eq!(
21762        wrap_with_prefix(
21763            "".to_string(),
21764            "".to_string(),
21765            "\thello world".to_string(),
21766            8,
21767            NonZeroU32::new(4).unwrap(),
21768            false,
21769        ),
21770        "hello\nworld"
21771    );
21772    assert_eq!(
21773        wrap_with_prefix(
21774            "// ".to_string(),
21775            "// ".to_string(),
21776            "xx \nyy zz aa bb cc".to_string(),
21777            12,
21778            NonZeroU32::new(4).unwrap(),
21779            false,
21780        ),
21781        "// xx yy zz\n// aa bb cc"
21782    );
21783    assert_eq!(
21784        wrap_with_prefix(
21785            String::new(),
21786            String::new(),
21787            "这是什么 \n 钢笔".to_string(),
21788            3,
21789            NonZeroU32::new(4).unwrap(),
21790            false,
21791        ),
21792        "这是什\n么 钢\n"
21793    );
21794}
21795
21796pub trait CollaborationHub {
21797    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21798    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21799    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21800}
21801
21802impl CollaborationHub for Entity<Project> {
21803    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21804        self.read(cx).collaborators()
21805    }
21806
21807    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21808        self.read(cx).user_store().read(cx).participant_indices()
21809    }
21810
21811    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21812        let this = self.read(cx);
21813        let user_ids = this.collaborators().values().map(|c| c.user_id);
21814        this.user_store().read(cx).participant_names(user_ids, cx)
21815    }
21816}
21817
21818pub trait SemanticsProvider {
21819    fn hover(
21820        &self,
21821        buffer: &Entity<Buffer>,
21822        position: text::Anchor,
21823        cx: &mut App,
21824    ) -> Option<Task<Vec<project::Hover>>>;
21825
21826    fn inline_values(
21827        &self,
21828        buffer_handle: Entity<Buffer>,
21829        range: Range<text::Anchor>,
21830        cx: &mut App,
21831    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21832
21833    fn inlay_hints(
21834        &self,
21835        buffer_handle: Entity<Buffer>,
21836        range: Range<text::Anchor>,
21837        cx: &mut App,
21838    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21839
21840    fn resolve_inlay_hint(
21841        &self,
21842        hint: InlayHint,
21843        buffer_handle: Entity<Buffer>,
21844        server_id: LanguageServerId,
21845        cx: &mut App,
21846    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21847
21848    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21849
21850    fn document_highlights(
21851        &self,
21852        buffer: &Entity<Buffer>,
21853        position: text::Anchor,
21854        cx: &mut App,
21855    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21856
21857    fn definitions(
21858        &self,
21859        buffer: &Entity<Buffer>,
21860        position: text::Anchor,
21861        kind: GotoDefinitionKind,
21862        cx: &mut App,
21863    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21864
21865    fn range_for_rename(
21866        &self,
21867        buffer: &Entity<Buffer>,
21868        position: text::Anchor,
21869        cx: &mut App,
21870    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21871
21872    fn perform_rename(
21873        &self,
21874        buffer: &Entity<Buffer>,
21875        position: text::Anchor,
21876        new_name: String,
21877        cx: &mut App,
21878    ) -> Option<Task<Result<ProjectTransaction>>>;
21879}
21880
21881pub trait CompletionProvider {
21882    fn completions(
21883        &self,
21884        excerpt_id: ExcerptId,
21885        buffer: &Entity<Buffer>,
21886        buffer_position: text::Anchor,
21887        trigger: CompletionContext,
21888        window: &mut Window,
21889        cx: &mut Context<Editor>,
21890    ) -> Task<Result<Vec<CompletionResponse>>>;
21891
21892    fn resolve_completions(
21893        &self,
21894        _buffer: Entity<Buffer>,
21895        _completion_indices: Vec<usize>,
21896        _completions: Rc<RefCell<Box<[Completion]>>>,
21897        _cx: &mut Context<Editor>,
21898    ) -> Task<Result<bool>> {
21899        Task::ready(Ok(false))
21900    }
21901
21902    fn apply_additional_edits_for_completion(
21903        &self,
21904        _buffer: Entity<Buffer>,
21905        _completions: Rc<RefCell<Box<[Completion]>>>,
21906        _completion_index: usize,
21907        _push_to_history: bool,
21908        _cx: &mut Context<Editor>,
21909    ) -> Task<Result<Option<language::Transaction>>> {
21910        Task::ready(Ok(None))
21911    }
21912
21913    fn is_completion_trigger(
21914        &self,
21915        buffer: &Entity<Buffer>,
21916        position: language::Anchor,
21917        text: &str,
21918        trigger_in_words: bool,
21919        menu_is_open: bool,
21920        cx: &mut Context<Editor>,
21921    ) -> bool;
21922
21923    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21924
21925    fn sort_completions(&self) -> bool {
21926        true
21927    }
21928
21929    fn filter_completions(&self) -> bool {
21930        true
21931    }
21932}
21933
21934pub trait CodeActionProvider {
21935    fn id(&self) -> Arc<str>;
21936
21937    fn code_actions(
21938        &self,
21939        buffer: &Entity<Buffer>,
21940        range: Range<text::Anchor>,
21941        window: &mut Window,
21942        cx: &mut App,
21943    ) -> Task<Result<Vec<CodeAction>>>;
21944
21945    fn apply_code_action(
21946        &self,
21947        buffer_handle: Entity<Buffer>,
21948        action: CodeAction,
21949        excerpt_id: ExcerptId,
21950        push_to_history: bool,
21951        window: &mut Window,
21952        cx: &mut App,
21953    ) -> Task<Result<ProjectTransaction>>;
21954}
21955
21956impl CodeActionProvider for Entity<Project> {
21957    fn id(&self) -> Arc<str> {
21958        "project".into()
21959    }
21960
21961    fn code_actions(
21962        &self,
21963        buffer: &Entity<Buffer>,
21964        range: Range<text::Anchor>,
21965        _window: &mut Window,
21966        cx: &mut App,
21967    ) -> Task<Result<Vec<CodeAction>>> {
21968        self.update(cx, |project, cx| {
21969            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
21970            let code_actions = project.code_actions(buffer, range, None, cx);
21971            cx.background_spawn(async move {
21972                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
21973                Ok(code_lens_actions
21974                    .context("code lens fetch")?
21975                    .into_iter()
21976                    .chain(code_actions.context("code action fetch")?)
21977                    .collect())
21978            })
21979        })
21980    }
21981
21982    fn apply_code_action(
21983        &self,
21984        buffer_handle: Entity<Buffer>,
21985        action: CodeAction,
21986        _excerpt_id: ExcerptId,
21987        push_to_history: bool,
21988        _window: &mut Window,
21989        cx: &mut App,
21990    ) -> Task<Result<ProjectTransaction>> {
21991        self.update(cx, |project, cx| {
21992            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21993        })
21994    }
21995}
21996
21997fn snippet_completions(
21998    project: &Project,
21999    buffer: &Entity<Buffer>,
22000    buffer_position: text::Anchor,
22001    cx: &mut App,
22002) -> Task<Result<CompletionResponse>> {
22003    let languages = buffer.read(cx).languages_at(buffer_position);
22004    let snippet_store = project.snippets().read(cx);
22005
22006    let scopes: Vec<_> = languages
22007        .iter()
22008        .filter_map(|language| {
22009            let language_name = language.lsp_id();
22010            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22011
22012            if snippets.is_empty() {
22013                None
22014            } else {
22015                Some((language.default_scope(), snippets))
22016            }
22017        })
22018        .collect();
22019
22020    if scopes.is_empty() {
22021        return Task::ready(Ok(CompletionResponse {
22022            completions: vec![],
22023            is_incomplete: false,
22024        }));
22025    }
22026
22027    let snapshot = buffer.read(cx).text_snapshot();
22028    let chars: String = snapshot
22029        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22030        .collect();
22031    let executor = cx.background_executor().clone();
22032
22033    cx.background_spawn(async move {
22034        let mut is_incomplete = false;
22035        let mut completions: Vec<Completion> = Vec::new();
22036        for (scope, snippets) in scopes.into_iter() {
22037            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22038            let mut last_word = chars
22039                .chars()
22040                .take_while(|c| classifier.is_word(*c))
22041                .collect::<String>();
22042            last_word = last_word.chars().rev().collect();
22043
22044            if last_word.is_empty() {
22045                return Ok(CompletionResponse {
22046                    completions: vec![],
22047                    is_incomplete: true,
22048                });
22049            }
22050
22051            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22052            let to_lsp = |point: &text::Anchor| {
22053                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22054                point_to_lsp(end)
22055            };
22056            let lsp_end = to_lsp(&buffer_position);
22057
22058            let candidates = snippets
22059                .iter()
22060                .enumerate()
22061                .flat_map(|(ix, snippet)| {
22062                    snippet
22063                        .prefix
22064                        .iter()
22065                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
22066                })
22067                .collect::<Vec<StringMatchCandidate>>();
22068
22069            const MAX_RESULTS: usize = 100;
22070            let mut matches = fuzzy::match_strings(
22071                &candidates,
22072                &last_word,
22073                last_word.chars().any(|c| c.is_uppercase()),
22074                true,
22075                MAX_RESULTS,
22076                &Default::default(),
22077                executor.clone(),
22078            )
22079            .await;
22080
22081            if matches.len() >= MAX_RESULTS {
22082                is_incomplete = true;
22083            }
22084
22085            // Remove all candidates where the query's start does not match the start of any word in the candidate
22086            if let Some(query_start) = last_word.chars().next() {
22087                matches.retain(|string_match| {
22088                    split_words(&string_match.string).any(|word| {
22089                        // Check that the first codepoint of the word as lowercase matches the first
22090                        // codepoint of the query as lowercase
22091                        word.chars()
22092                            .flat_map(|codepoint| codepoint.to_lowercase())
22093                            .zip(query_start.to_lowercase())
22094                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22095                    })
22096                });
22097            }
22098
22099            let matched_strings = matches
22100                .into_iter()
22101                .map(|m| m.string)
22102                .collect::<HashSet<_>>();
22103
22104            completions.extend(snippets.iter().filter_map(|snippet| {
22105                let matching_prefix = snippet
22106                    .prefix
22107                    .iter()
22108                    .find(|prefix| matched_strings.contains(*prefix))?;
22109                let start = as_offset - last_word.len();
22110                let start = snapshot.anchor_before(start);
22111                let range = start..buffer_position;
22112                let lsp_start = to_lsp(&start);
22113                let lsp_range = lsp::Range {
22114                    start: lsp_start,
22115                    end: lsp_end,
22116                };
22117                Some(Completion {
22118                    replace_range: range,
22119                    new_text: snippet.body.clone(),
22120                    source: CompletionSource::Lsp {
22121                        insert_range: None,
22122                        server_id: LanguageServerId(usize::MAX),
22123                        resolved: true,
22124                        lsp_completion: Box::new(lsp::CompletionItem {
22125                            label: snippet.prefix.first().unwrap().clone(),
22126                            kind: Some(CompletionItemKind::SNIPPET),
22127                            label_details: snippet.description.as_ref().map(|description| {
22128                                lsp::CompletionItemLabelDetails {
22129                                    detail: Some(description.clone()),
22130                                    description: None,
22131                                }
22132                            }),
22133                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22134                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22135                                lsp::InsertReplaceEdit {
22136                                    new_text: snippet.body.clone(),
22137                                    insert: lsp_range,
22138                                    replace: lsp_range,
22139                                },
22140                            )),
22141                            filter_text: Some(snippet.body.clone()),
22142                            sort_text: Some(char::MAX.to_string()),
22143                            ..lsp::CompletionItem::default()
22144                        }),
22145                        lsp_defaults: None,
22146                    },
22147                    label: CodeLabel {
22148                        text: matching_prefix.clone(),
22149                        runs: Vec::new(),
22150                        filter_range: 0..matching_prefix.len(),
22151                    },
22152                    icon_path: None,
22153                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22154                        single_line: snippet.name.clone().into(),
22155                        plain_text: snippet
22156                            .description
22157                            .clone()
22158                            .map(|description| description.into()),
22159                    }),
22160                    insert_text_mode: None,
22161                    confirm: None,
22162                })
22163            }))
22164        }
22165
22166        Ok(CompletionResponse {
22167            completions,
22168            is_incomplete,
22169        })
22170    })
22171}
22172
22173impl CompletionProvider for Entity<Project> {
22174    fn completions(
22175        &self,
22176        _excerpt_id: ExcerptId,
22177        buffer: &Entity<Buffer>,
22178        buffer_position: text::Anchor,
22179        options: CompletionContext,
22180        _window: &mut Window,
22181        cx: &mut Context<Editor>,
22182    ) -> Task<Result<Vec<CompletionResponse>>> {
22183        self.update(cx, |project, cx| {
22184            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22185            let project_completions = project.completions(buffer, buffer_position, options, cx);
22186            cx.background_spawn(async move {
22187                let mut responses = project_completions.await?;
22188                let snippets = snippets.await?;
22189                if !snippets.completions.is_empty() {
22190                    responses.push(snippets);
22191                }
22192                Ok(responses)
22193            })
22194        })
22195    }
22196
22197    fn resolve_completions(
22198        &self,
22199        buffer: Entity<Buffer>,
22200        completion_indices: Vec<usize>,
22201        completions: Rc<RefCell<Box<[Completion]>>>,
22202        cx: &mut Context<Editor>,
22203    ) -> Task<Result<bool>> {
22204        self.update(cx, |project, cx| {
22205            project.lsp_store().update(cx, |lsp_store, cx| {
22206                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22207            })
22208        })
22209    }
22210
22211    fn apply_additional_edits_for_completion(
22212        &self,
22213        buffer: Entity<Buffer>,
22214        completions: Rc<RefCell<Box<[Completion]>>>,
22215        completion_index: usize,
22216        push_to_history: bool,
22217        cx: &mut Context<Editor>,
22218    ) -> Task<Result<Option<language::Transaction>>> {
22219        self.update(cx, |project, cx| {
22220            project.lsp_store().update(cx, |lsp_store, cx| {
22221                lsp_store.apply_additional_edits_for_completion(
22222                    buffer,
22223                    completions,
22224                    completion_index,
22225                    push_to_history,
22226                    cx,
22227                )
22228            })
22229        })
22230    }
22231
22232    fn is_completion_trigger(
22233        &self,
22234        buffer: &Entity<Buffer>,
22235        position: language::Anchor,
22236        text: &str,
22237        trigger_in_words: bool,
22238        menu_is_open: bool,
22239        cx: &mut Context<Editor>,
22240    ) -> bool {
22241        let mut chars = text.chars();
22242        let char = if let Some(char) = chars.next() {
22243            char
22244        } else {
22245            return false;
22246        };
22247        if chars.next().is_some() {
22248            return false;
22249        }
22250
22251        let buffer = buffer.read(cx);
22252        let snapshot = buffer.snapshot();
22253        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22254            return false;
22255        }
22256        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22257        if trigger_in_words && classifier.is_word(char) {
22258            return true;
22259        }
22260
22261        buffer.completion_triggers().contains(text)
22262    }
22263}
22264
22265impl SemanticsProvider for Entity<Project> {
22266    fn hover(
22267        &self,
22268        buffer: &Entity<Buffer>,
22269        position: text::Anchor,
22270        cx: &mut App,
22271    ) -> Option<Task<Vec<project::Hover>>> {
22272        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22273    }
22274
22275    fn document_highlights(
22276        &self,
22277        buffer: &Entity<Buffer>,
22278        position: text::Anchor,
22279        cx: &mut App,
22280    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22281        Some(self.update(cx, |project, cx| {
22282            project.document_highlights(buffer, position, cx)
22283        }))
22284    }
22285
22286    fn definitions(
22287        &self,
22288        buffer: &Entity<Buffer>,
22289        position: text::Anchor,
22290        kind: GotoDefinitionKind,
22291        cx: &mut App,
22292    ) -> Option<Task<Result<Vec<LocationLink>>>> {
22293        Some(self.update(cx, |project, cx| match kind {
22294            GotoDefinitionKind::Symbol => project.definitions(&buffer, position, cx),
22295            GotoDefinitionKind::Declaration => project.declarations(&buffer, position, cx),
22296            GotoDefinitionKind::Type => project.type_definitions(&buffer, position, cx),
22297            GotoDefinitionKind::Implementation => project.implementations(&buffer, position, cx),
22298        }))
22299    }
22300
22301    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22302        self.update(cx, |project, cx| {
22303            if project
22304                .active_debug_session(cx)
22305                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22306            {
22307                return true;
22308            }
22309
22310            buffer.update(cx, |buffer, cx| {
22311                project.any_language_server_supports_inlay_hints(buffer, cx)
22312            })
22313        })
22314    }
22315
22316    fn inline_values(
22317        &self,
22318        buffer_handle: Entity<Buffer>,
22319        range: Range<text::Anchor>,
22320        cx: &mut App,
22321    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22322        self.update(cx, |project, cx| {
22323            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22324
22325            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22326        })
22327    }
22328
22329    fn inlay_hints(
22330        &self,
22331        buffer_handle: Entity<Buffer>,
22332        range: Range<text::Anchor>,
22333        cx: &mut App,
22334    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22335        Some(self.update(cx, |project, cx| {
22336            project.inlay_hints(buffer_handle, range, cx)
22337        }))
22338    }
22339
22340    fn resolve_inlay_hint(
22341        &self,
22342        hint: InlayHint,
22343        buffer_handle: Entity<Buffer>,
22344        server_id: LanguageServerId,
22345        cx: &mut App,
22346    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22347        Some(self.update(cx, |project, cx| {
22348            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22349        }))
22350    }
22351
22352    fn range_for_rename(
22353        &self,
22354        buffer: &Entity<Buffer>,
22355        position: text::Anchor,
22356        cx: &mut App,
22357    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22358        Some(self.update(cx, |project, cx| {
22359            let buffer = buffer.clone();
22360            let task = project.prepare_rename(buffer.clone(), position, cx);
22361            cx.spawn(async move |_, cx| {
22362                Ok(match task.await? {
22363                    PrepareRenameResponse::Success(range) => Some(range),
22364                    PrepareRenameResponse::InvalidPosition => None,
22365                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22366                        // Fallback on using TreeSitter info to determine identifier range
22367                        buffer.read_with(cx, |buffer, _| {
22368                            let snapshot = buffer.snapshot();
22369                            let (range, kind) = snapshot.surrounding_word(position, false);
22370                            if kind != Some(CharKind::Word) {
22371                                return None;
22372                            }
22373                            Some(
22374                                snapshot.anchor_before(range.start)
22375                                    ..snapshot.anchor_after(range.end),
22376                            )
22377                        })?
22378                    }
22379                })
22380            })
22381        }))
22382    }
22383
22384    fn perform_rename(
22385        &self,
22386        buffer: &Entity<Buffer>,
22387        position: text::Anchor,
22388        new_name: String,
22389        cx: &mut App,
22390    ) -> Option<Task<Result<ProjectTransaction>>> {
22391        Some(self.update(cx, |project, cx| {
22392            project.perform_rename(buffer.clone(), position, new_name, cx)
22393        }))
22394    }
22395}
22396
22397fn inlay_hint_settings(
22398    location: Anchor,
22399    snapshot: &MultiBufferSnapshot,
22400    cx: &mut Context<Editor>,
22401) -> InlayHintSettings {
22402    let file = snapshot.file_at(location);
22403    let language = snapshot.language_at(location).map(|l| l.name());
22404    language_settings(language, file, cx).inlay_hints
22405}
22406
22407fn consume_contiguous_rows(
22408    contiguous_row_selections: &mut Vec<Selection<Point>>,
22409    selection: &Selection<Point>,
22410    display_map: &DisplaySnapshot,
22411    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22412) -> (MultiBufferRow, MultiBufferRow) {
22413    contiguous_row_selections.push(selection.clone());
22414    let start_row = starting_row(selection, display_map);
22415    let mut end_row = ending_row(selection, display_map);
22416
22417    while let Some(next_selection) = selections.peek() {
22418        if next_selection.start.row <= end_row.0 {
22419            end_row = ending_row(next_selection, display_map);
22420            contiguous_row_selections.push(selections.next().unwrap().clone());
22421        } else {
22422            break;
22423        }
22424    }
22425    (start_row, end_row)
22426}
22427
22428fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22429    if selection.start.column > 0 {
22430        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22431    } else {
22432        MultiBufferRow(selection.start.row)
22433    }
22434}
22435
22436fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22437    if next_selection.end.column > 0 || next_selection.is_empty() {
22438        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22439    } else {
22440        MultiBufferRow(next_selection.end.row)
22441    }
22442}
22443
22444impl EditorSnapshot {
22445    pub fn remote_selections_in_range<'a>(
22446        &'a self,
22447        range: &'a Range<Anchor>,
22448        collaboration_hub: &dyn CollaborationHub,
22449        cx: &'a App,
22450    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22451        let participant_names = collaboration_hub.user_names(cx);
22452        let participant_indices = collaboration_hub.user_participant_indices(cx);
22453        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22454        let collaborators_by_replica_id = collaborators_by_peer_id
22455            .values()
22456            .map(|collaborator| (collaborator.replica_id, collaborator))
22457            .collect::<HashMap<_, _>>();
22458        self.buffer_snapshot
22459            .selections_in_range(range, false)
22460            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22461                if replica_id == AGENT_REPLICA_ID {
22462                    Some(RemoteSelection {
22463                        replica_id,
22464                        selection,
22465                        cursor_shape,
22466                        line_mode,
22467                        collaborator_id: CollaboratorId::Agent,
22468                        user_name: Some("Agent".into()),
22469                        color: cx.theme().players().agent(),
22470                    })
22471                } else {
22472                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22473                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22474                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22475                    Some(RemoteSelection {
22476                        replica_id,
22477                        selection,
22478                        cursor_shape,
22479                        line_mode,
22480                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22481                        user_name,
22482                        color: if let Some(index) = participant_index {
22483                            cx.theme().players().color_for_participant(index.0)
22484                        } else {
22485                            cx.theme().players().absent()
22486                        },
22487                    })
22488                }
22489            })
22490    }
22491
22492    pub fn hunks_for_ranges(
22493        &self,
22494        ranges: impl IntoIterator<Item = Range<Point>>,
22495    ) -> Vec<MultiBufferDiffHunk> {
22496        let mut hunks = Vec::new();
22497        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22498            HashMap::default();
22499        for query_range in ranges {
22500            let query_rows =
22501                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22502            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22503                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22504            ) {
22505                // Include deleted hunks that are adjacent to the query range, because
22506                // otherwise they would be missed.
22507                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22508                if hunk.status().is_deleted() {
22509                    intersects_range |= hunk.row_range.start == query_rows.end;
22510                    intersects_range |= hunk.row_range.end == query_rows.start;
22511                }
22512                if intersects_range {
22513                    if !processed_buffer_rows
22514                        .entry(hunk.buffer_id)
22515                        .or_default()
22516                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22517                    {
22518                        continue;
22519                    }
22520                    hunks.push(hunk);
22521                }
22522            }
22523        }
22524
22525        hunks
22526    }
22527
22528    fn display_diff_hunks_for_rows<'a>(
22529        &'a self,
22530        display_rows: Range<DisplayRow>,
22531        folded_buffers: &'a HashSet<BufferId>,
22532    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22533        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22534        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22535
22536        self.buffer_snapshot
22537            .diff_hunks_in_range(buffer_start..buffer_end)
22538            .filter_map(|hunk| {
22539                if folded_buffers.contains(&hunk.buffer_id) {
22540                    return None;
22541                }
22542
22543                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22544                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22545
22546                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22547                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22548
22549                let display_hunk = if hunk_display_start.column() != 0 {
22550                    DisplayDiffHunk::Folded {
22551                        display_row: hunk_display_start.row(),
22552                    }
22553                } else {
22554                    let mut end_row = hunk_display_end.row();
22555                    if hunk_display_end.column() > 0 {
22556                        end_row.0 += 1;
22557                    }
22558                    let is_created_file = hunk.is_created_file();
22559                    DisplayDiffHunk::Unfolded {
22560                        status: hunk.status(),
22561                        diff_base_byte_range: hunk.diff_base_byte_range,
22562                        display_row_range: hunk_display_start.row()..end_row,
22563                        multi_buffer_range: Anchor::range_in_buffer(
22564                            hunk.excerpt_id,
22565                            hunk.buffer_id,
22566                            hunk.buffer_range,
22567                        ),
22568                        is_created_file,
22569                    }
22570                };
22571
22572                Some(display_hunk)
22573            })
22574    }
22575
22576    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22577        self.display_snapshot.buffer_snapshot.language_at(position)
22578    }
22579
22580    pub fn is_focused(&self) -> bool {
22581        self.is_focused
22582    }
22583
22584    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22585        self.placeholder_text.as_ref()
22586    }
22587
22588    pub fn scroll_position(&self) -> gpui::Point<f32> {
22589        self.scroll_anchor.scroll_position(&self.display_snapshot)
22590    }
22591
22592    fn gutter_dimensions(
22593        &self,
22594        font_id: FontId,
22595        font_size: Pixels,
22596        max_line_number_width: Pixels,
22597        cx: &App,
22598    ) -> Option<GutterDimensions> {
22599        if !self.show_gutter {
22600            return None;
22601        }
22602
22603        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22604        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22605
22606        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22607            matches!(
22608                ProjectSettings::get_global(cx).git.git_gutter,
22609                Some(GitGutterSetting::TrackedFiles)
22610            )
22611        });
22612        let gutter_settings = EditorSettings::get_global(cx).gutter;
22613        let show_line_numbers = self
22614            .show_line_numbers
22615            .unwrap_or(gutter_settings.line_numbers);
22616        let line_gutter_width = if show_line_numbers {
22617            // Avoid flicker-like gutter resizes when the line number gains another digit by
22618            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22619            let min_width_for_number_on_gutter =
22620                ch_advance * gutter_settings.min_line_number_digits as f32;
22621            max_line_number_width.max(min_width_for_number_on_gutter)
22622        } else {
22623            0.0.into()
22624        };
22625
22626        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22627        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22628
22629        let git_blame_entries_width =
22630            self.git_blame_gutter_max_author_length
22631                .map(|max_author_length| {
22632                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22633                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22634
22635                    /// The number of characters to dedicate to gaps and margins.
22636                    const SPACING_WIDTH: usize = 4;
22637
22638                    let max_char_count = max_author_length.min(renderer.max_author_length())
22639                        + ::git::SHORT_SHA_LENGTH
22640                        + MAX_RELATIVE_TIMESTAMP.len()
22641                        + SPACING_WIDTH;
22642
22643                    ch_advance * max_char_count
22644                });
22645
22646        let is_singleton = self.buffer_snapshot.is_singleton();
22647
22648        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22649        left_padding += if !is_singleton {
22650            ch_width * 4.0
22651        } else if show_runnables || show_breakpoints {
22652            ch_width * 3.0
22653        } else if show_git_gutter && show_line_numbers {
22654            ch_width * 2.0
22655        } else if show_git_gutter || show_line_numbers {
22656            ch_width
22657        } else {
22658            px(0.)
22659        };
22660
22661        let shows_folds = is_singleton && gutter_settings.folds;
22662
22663        let right_padding = if shows_folds && show_line_numbers {
22664            ch_width * 4.0
22665        } else if shows_folds || (!is_singleton && show_line_numbers) {
22666            ch_width * 3.0
22667        } else if show_line_numbers {
22668            ch_width
22669        } else {
22670            px(0.)
22671        };
22672
22673        Some(GutterDimensions {
22674            left_padding,
22675            right_padding,
22676            width: line_gutter_width + left_padding + right_padding,
22677            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22678            git_blame_entries_width,
22679        })
22680    }
22681
22682    pub fn render_crease_toggle(
22683        &self,
22684        buffer_row: MultiBufferRow,
22685        row_contains_cursor: bool,
22686        editor: Entity<Editor>,
22687        window: &mut Window,
22688        cx: &mut App,
22689    ) -> Option<AnyElement> {
22690        let folded = self.is_line_folded(buffer_row);
22691        let mut is_foldable = false;
22692
22693        if let Some(crease) = self
22694            .crease_snapshot
22695            .query_row(buffer_row, &self.buffer_snapshot)
22696        {
22697            is_foldable = true;
22698            match crease {
22699                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22700                    if let Some(render_toggle) = render_toggle {
22701                        let toggle_callback =
22702                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22703                                if folded {
22704                                    editor.update(cx, |editor, cx| {
22705                                        editor.fold_at(buffer_row, window, cx)
22706                                    });
22707                                } else {
22708                                    editor.update(cx, |editor, cx| {
22709                                        editor.unfold_at(buffer_row, window, cx)
22710                                    });
22711                                }
22712                            });
22713                        return Some((render_toggle)(
22714                            buffer_row,
22715                            folded,
22716                            toggle_callback,
22717                            window,
22718                            cx,
22719                        ));
22720                    }
22721                }
22722            }
22723        }
22724
22725        is_foldable |= self.starts_indent(buffer_row);
22726
22727        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22728            Some(
22729                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22730                    .toggle_state(folded)
22731                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22732                        if folded {
22733                            this.unfold_at(buffer_row, window, cx);
22734                        } else {
22735                            this.fold_at(buffer_row, window, cx);
22736                        }
22737                    }))
22738                    .into_any_element(),
22739            )
22740        } else {
22741            None
22742        }
22743    }
22744
22745    pub fn render_crease_trailer(
22746        &self,
22747        buffer_row: MultiBufferRow,
22748        window: &mut Window,
22749        cx: &mut App,
22750    ) -> Option<AnyElement> {
22751        let folded = self.is_line_folded(buffer_row);
22752        if let Crease::Inline { render_trailer, .. } = self
22753            .crease_snapshot
22754            .query_row(buffer_row, &self.buffer_snapshot)?
22755        {
22756            let render_trailer = render_trailer.as_ref()?;
22757            Some(render_trailer(buffer_row, folded, window, cx))
22758        } else {
22759            None
22760        }
22761    }
22762}
22763
22764impl Deref for EditorSnapshot {
22765    type Target = DisplaySnapshot;
22766
22767    fn deref(&self) -> &Self::Target {
22768        &self.display_snapshot
22769    }
22770}
22771
22772#[derive(Clone, Debug, PartialEq, Eq)]
22773pub enum EditorEvent {
22774    InputIgnored {
22775        text: Arc<str>,
22776    },
22777    InputHandled {
22778        utf16_range_to_replace: Option<Range<isize>>,
22779        text: Arc<str>,
22780    },
22781    ExcerptsAdded {
22782        buffer: Entity<Buffer>,
22783        predecessor: ExcerptId,
22784        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22785    },
22786    ExcerptsRemoved {
22787        ids: Vec<ExcerptId>,
22788        removed_buffer_ids: Vec<BufferId>,
22789    },
22790    BufferFoldToggled {
22791        ids: Vec<ExcerptId>,
22792        folded: bool,
22793    },
22794    ExcerptsEdited {
22795        ids: Vec<ExcerptId>,
22796    },
22797    ExcerptsExpanded {
22798        ids: Vec<ExcerptId>,
22799    },
22800    BufferEdited,
22801    Edited {
22802        transaction_id: clock::Lamport,
22803    },
22804    Reparsed(BufferId),
22805    Focused,
22806    FocusedIn,
22807    Blurred,
22808    DirtyChanged,
22809    Saved,
22810    TitleChanged,
22811    DiffBaseChanged,
22812    SelectionsChanged {
22813        local: bool,
22814    },
22815    ScrollPositionChanged {
22816        local: bool,
22817        autoscroll: bool,
22818    },
22819    Closed,
22820    TransactionUndone {
22821        transaction_id: clock::Lamport,
22822    },
22823    TransactionBegun {
22824        transaction_id: clock::Lamport,
22825    },
22826    Reloaded,
22827    CursorShapeChanged,
22828    PushedToNavHistory {
22829        anchor: Anchor,
22830        is_deactivate: bool,
22831    },
22832}
22833
22834impl EventEmitter<EditorEvent> for Editor {}
22835
22836impl Focusable for Editor {
22837    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22838        self.focus_handle.clone()
22839    }
22840}
22841
22842impl Render for Editor {
22843    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22844        let settings = ThemeSettings::get_global(cx);
22845
22846        let mut text_style = match self.mode {
22847            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22848                color: cx.theme().colors().editor_foreground,
22849                font_family: settings.ui_font.family.clone(),
22850                font_features: settings.ui_font.features.clone(),
22851                font_fallbacks: settings.ui_font.fallbacks.clone(),
22852                font_size: rems(0.875).into(),
22853                font_weight: settings.ui_font.weight,
22854                line_height: relative(settings.buffer_line_height.value()),
22855                ..Default::default()
22856            },
22857            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22858                color: cx.theme().colors().editor_foreground,
22859                font_family: settings.buffer_font.family.clone(),
22860                font_features: settings.buffer_font.features.clone(),
22861                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22862                font_size: settings.buffer_font_size(cx).into(),
22863                font_weight: settings.buffer_font.weight,
22864                line_height: relative(settings.buffer_line_height.value()),
22865                ..Default::default()
22866            },
22867        };
22868        if let Some(text_style_refinement) = &self.text_style_refinement {
22869            text_style.refine(text_style_refinement)
22870        }
22871
22872        let background = match self.mode {
22873            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22874            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22875            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22876            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22877        };
22878
22879        EditorElement::new(
22880            &cx.entity(),
22881            EditorStyle {
22882                background,
22883                border: cx.theme().colors().border,
22884                local_player: cx.theme().players().local(),
22885                text: text_style,
22886                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22887                syntax: cx.theme().syntax().clone(),
22888                status: cx.theme().status().clone(),
22889                inlay_hints_style: make_inlay_hints_style(cx),
22890                edit_prediction_styles: make_suggestion_styles(cx),
22891                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22892                show_underlines: self.diagnostics_enabled(),
22893            },
22894        )
22895    }
22896}
22897
22898impl EntityInputHandler for Editor {
22899    fn text_for_range(
22900        &mut self,
22901        range_utf16: Range<usize>,
22902        adjusted_range: &mut Option<Range<usize>>,
22903        _: &mut Window,
22904        cx: &mut Context<Self>,
22905    ) -> Option<String> {
22906        let snapshot = self.buffer.read(cx).read(cx);
22907        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22908        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22909        if (start.0..end.0) != range_utf16 {
22910            adjusted_range.replace(start.0..end.0);
22911        }
22912        Some(snapshot.text_for_range(start..end).collect())
22913    }
22914
22915    fn selected_text_range(
22916        &mut self,
22917        ignore_disabled_input: bool,
22918        _: &mut Window,
22919        cx: &mut Context<Self>,
22920    ) -> Option<UTF16Selection> {
22921        // Prevent the IME menu from appearing when holding down an alphabetic key
22922        // while input is disabled.
22923        if !ignore_disabled_input && !self.input_enabled {
22924            return None;
22925        }
22926
22927        let selection = self.selections.newest::<OffsetUtf16>(cx);
22928        let range = selection.range();
22929
22930        Some(UTF16Selection {
22931            range: range.start.0..range.end.0,
22932            reversed: selection.reversed,
22933        })
22934    }
22935
22936    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22937        let snapshot = self.buffer.read(cx).read(cx);
22938        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22939        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22940    }
22941
22942    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22943        self.clear_highlights::<InputComposition>(cx);
22944        self.ime_transaction.take();
22945    }
22946
22947    fn replace_text_in_range(
22948        &mut self,
22949        range_utf16: Option<Range<usize>>,
22950        text: &str,
22951        window: &mut Window,
22952        cx: &mut Context<Self>,
22953    ) {
22954        if !self.input_enabled {
22955            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22956            return;
22957        }
22958
22959        self.transact(window, cx, |this, window, cx| {
22960            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22961                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22962                Some(this.selection_replacement_ranges(range_utf16, cx))
22963            } else {
22964                this.marked_text_ranges(cx)
22965            };
22966
22967            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22968                let newest_selection_id = this.selections.newest_anchor().id;
22969                this.selections
22970                    .all::<OffsetUtf16>(cx)
22971                    .iter()
22972                    .zip(ranges_to_replace.iter())
22973                    .find_map(|(selection, range)| {
22974                        if selection.id == newest_selection_id {
22975                            Some(
22976                                (range.start.0 as isize - selection.head().0 as isize)
22977                                    ..(range.end.0 as isize - selection.head().0 as isize),
22978                            )
22979                        } else {
22980                            None
22981                        }
22982                    })
22983            });
22984
22985            cx.emit(EditorEvent::InputHandled {
22986                utf16_range_to_replace: range_to_replace,
22987                text: text.into(),
22988            });
22989
22990            if let Some(new_selected_ranges) = new_selected_ranges {
22991                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22992                    selections.select_ranges(new_selected_ranges)
22993                });
22994                this.backspace(&Default::default(), window, cx);
22995            }
22996
22997            this.handle_input(text, window, cx);
22998        });
22999
23000        if let Some(transaction) = self.ime_transaction {
23001            self.buffer.update(cx, |buffer, cx| {
23002                buffer.group_until_transaction(transaction, cx);
23003            });
23004        }
23005
23006        self.unmark_text(window, cx);
23007    }
23008
23009    fn replace_and_mark_text_in_range(
23010        &mut self,
23011        range_utf16: Option<Range<usize>>,
23012        text: &str,
23013        new_selected_range_utf16: Option<Range<usize>>,
23014        window: &mut Window,
23015        cx: &mut Context<Self>,
23016    ) {
23017        if !self.input_enabled {
23018            return;
23019        }
23020
23021        let transaction = self.transact(window, cx, |this, window, cx| {
23022            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23023                let snapshot = this.buffer.read(cx).read(cx);
23024                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23025                    for marked_range in &mut marked_ranges {
23026                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23027                        marked_range.start.0 += relative_range_utf16.start;
23028                        marked_range.start =
23029                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23030                        marked_range.end =
23031                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23032                    }
23033                }
23034                Some(marked_ranges)
23035            } else if let Some(range_utf16) = range_utf16 {
23036                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23037                Some(this.selection_replacement_ranges(range_utf16, cx))
23038            } else {
23039                None
23040            };
23041
23042            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23043                let newest_selection_id = this.selections.newest_anchor().id;
23044                this.selections
23045                    .all::<OffsetUtf16>(cx)
23046                    .iter()
23047                    .zip(ranges_to_replace.iter())
23048                    .find_map(|(selection, range)| {
23049                        if selection.id == newest_selection_id {
23050                            Some(
23051                                (range.start.0 as isize - selection.head().0 as isize)
23052                                    ..(range.end.0 as isize - selection.head().0 as isize),
23053                            )
23054                        } else {
23055                            None
23056                        }
23057                    })
23058            });
23059
23060            cx.emit(EditorEvent::InputHandled {
23061                utf16_range_to_replace: range_to_replace,
23062                text: text.into(),
23063            });
23064
23065            if let Some(ranges) = ranges_to_replace {
23066                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23067                    s.select_ranges(ranges)
23068                });
23069            }
23070
23071            let marked_ranges = {
23072                let snapshot = this.buffer.read(cx).read(cx);
23073                this.selections
23074                    .disjoint_anchors()
23075                    .iter()
23076                    .map(|selection| {
23077                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23078                    })
23079                    .collect::<Vec<_>>()
23080            };
23081
23082            if text.is_empty() {
23083                this.unmark_text(window, cx);
23084            } else {
23085                this.highlight_text::<InputComposition>(
23086                    marked_ranges.clone(),
23087                    HighlightStyle {
23088                        underline: Some(UnderlineStyle {
23089                            thickness: px(1.),
23090                            color: None,
23091                            wavy: false,
23092                        }),
23093                        ..Default::default()
23094                    },
23095                    cx,
23096                );
23097            }
23098
23099            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23100            let use_autoclose = this.use_autoclose;
23101            let use_auto_surround = this.use_auto_surround;
23102            this.set_use_autoclose(false);
23103            this.set_use_auto_surround(false);
23104            this.handle_input(text, window, cx);
23105            this.set_use_autoclose(use_autoclose);
23106            this.set_use_auto_surround(use_auto_surround);
23107
23108            if let Some(new_selected_range) = new_selected_range_utf16 {
23109                let snapshot = this.buffer.read(cx).read(cx);
23110                let new_selected_ranges = marked_ranges
23111                    .into_iter()
23112                    .map(|marked_range| {
23113                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23114                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23115                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23116                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23117                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23118                    })
23119                    .collect::<Vec<_>>();
23120
23121                drop(snapshot);
23122                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23123                    selections.select_ranges(new_selected_ranges)
23124                });
23125            }
23126        });
23127
23128        self.ime_transaction = self.ime_transaction.or(transaction);
23129        if let Some(transaction) = self.ime_transaction {
23130            self.buffer.update(cx, |buffer, cx| {
23131                buffer.group_until_transaction(transaction, cx);
23132            });
23133        }
23134
23135        if self.text_highlights::<InputComposition>(cx).is_none() {
23136            self.ime_transaction.take();
23137        }
23138    }
23139
23140    fn bounds_for_range(
23141        &mut self,
23142        range_utf16: Range<usize>,
23143        element_bounds: gpui::Bounds<Pixels>,
23144        window: &mut Window,
23145        cx: &mut Context<Self>,
23146    ) -> Option<gpui::Bounds<Pixels>> {
23147        let text_layout_details = self.text_layout_details(window);
23148        let CharacterDimensions {
23149            em_width,
23150            em_advance,
23151            line_height,
23152        } = self.character_dimensions(window);
23153
23154        let snapshot = self.snapshot(window, cx);
23155        let scroll_position = snapshot.scroll_position();
23156        let scroll_left = scroll_position.x * em_advance;
23157
23158        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23159        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23160            + self.gutter_dimensions.full_width();
23161        let y = line_height * (start.row().as_f32() - scroll_position.y);
23162
23163        Some(Bounds {
23164            origin: element_bounds.origin + point(x, y),
23165            size: size(em_width, line_height),
23166        })
23167    }
23168
23169    fn character_index_for_point(
23170        &mut self,
23171        point: gpui::Point<Pixels>,
23172        _window: &mut Window,
23173        _cx: &mut Context<Self>,
23174    ) -> Option<usize> {
23175        let position_map = self.last_position_map.as_ref()?;
23176        if !position_map.text_hitbox.contains(&point) {
23177            return None;
23178        }
23179        let display_point = position_map.point_for_position(point).previous_valid;
23180        let anchor = position_map
23181            .snapshot
23182            .display_point_to_anchor(display_point, Bias::Left);
23183        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23184        Some(utf16_offset.0)
23185    }
23186}
23187
23188trait SelectionExt {
23189    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23190    fn spanned_rows(
23191        &self,
23192        include_end_if_at_line_start: bool,
23193        map: &DisplaySnapshot,
23194    ) -> Range<MultiBufferRow>;
23195}
23196
23197impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23198    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23199        let start = self
23200            .start
23201            .to_point(&map.buffer_snapshot)
23202            .to_display_point(map);
23203        let end = self
23204            .end
23205            .to_point(&map.buffer_snapshot)
23206            .to_display_point(map);
23207        if self.reversed {
23208            end..start
23209        } else {
23210            start..end
23211        }
23212    }
23213
23214    fn spanned_rows(
23215        &self,
23216        include_end_if_at_line_start: bool,
23217        map: &DisplaySnapshot,
23218    ) -> Range<MultiBufferRow> {
23219        let start = self.start.to_point(&map.buffer_snapshot);
23220        let mut end = self.end.to_point(&map.buffer_snapshot);
23221        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23222            end.row -= 1;
23223        }
23224
23225        let buffer_start = map.prev_line_boundary(start).0;
23226        let buffer_end = map.next_line_boundary(end).0;
23227        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23228    }
23229}
23230
23231impl<T: InvalidationRegion> InvalidationStack<T> {
23232    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23233    where
23234        S: Clone + ToOffset,
23235    {
23236        while let Some(region) = self.last() {
23237            let all_selections_inside_invalidation_ranges =
23238                if selections.len() == region.ranges().len() {
23239                    selections
23240                        .iter()
23241                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23242                        .all(|(selection, invalidation_range)| {
23243                            let head = selection.head().to_offset(buffer);
23244                            invalidation_range.start <= head && invalidation_range.end >= head
23245                        })
23246                } else {
23247                    false
23248                };
23249
23250            if all_selections_inside_invalidation_ranges {
23251                break;
23252            } else {
23253                self.pop();
23254            }
23255        }
23256    }
23257}
23258
23259impl<T> Default for InvalidationStack<T> {
23260    fn default() -> Self {
23261        Self(Default::default())
23262    }
23263}
23264
23265impl<T> Deref for InvalidationStack<T> {
23266    type Target = Vec<T>;
23267
23268    fn deref(&self) -> &Self::Target {
23269        &self.0
23270    }
23271}
23272
23273impl<T> DerefMut for InvalidationStack<T> {
23274    fn deref_mut(&mut self) -> &mut Self::Target {
23275        &mut self.0
23276    }
23277}
23278
23279impl InvalidationRegion for SnippetState {
23280    fn ranges(&self) -> &[Range<Anchor>] {
23281        &self.ranges[self.active_index]
23282    }
23283}
23284
23285fn edit_prediction_edit_text(
23286    current_snapshot: &BufferSnapshot,
23287    edits: &[(Range<Anchor>, String)],
23288    edit_preview: &EditPreview,
23289    include_deletions: bool,
23290    cx: &App,
23291) -> HighlightedText {
23292    let edits = edits
23293        .iter()
23294        .map(|(anchor, text)| {
23295            (
23296                anchor.start.text_anchor..anchor.end.text_anchor,
23297                text.clone(),
23298            )
23299        })
23300        .collect::<Vec<_>>();
23301
23302    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23303}
23304
23305fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23306    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23307    // Just show the raw edit text with basic styling
23308    let mut text = String::new();
23309    let mut highlights = Vec::new();
23310
23311    let insertion_highlight_style = HighlightStyle {
23312        color: Some(cx.theme().colors().text),
23313        ..Default::default()
23314    };
23315
23316    for (_, edit_text) in edits {
23317        let start_offset = text.len();
23318        text.push_str(edit_text);
23319        let end_offset = text.len();
23320
23321        if start_offset < end_offset {
23322            highlights.push((start_offset..end_offset, insertion_highlight_style));
23323        }
23324    }
23325
23326    HighlightedText {
23327        text: text.into(),
23328        highlights,
23329    }
23330}
23331
23332pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23333    match severity {
23334        lsp::DiagnosticSeverity::ERROR => colors.error,
23335        lsp::DiagnosticSeverity::WARNING => colors.warning,
23336        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23337        lsp::DiagnosticSeverity::HINT => colors.info,
23338        _ => colors.ignored,
23339    }
23340}
23341
23342pub fn styled_runs_for_code_label<'a>(
23343    label: &'a CodeLabel,
23344    syntax_theme: &'a theme::SyntaxTheme,
23345) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23346    let fade_out = HighlightStyle {
23347        fade_out: Some(0.35),
23348        ..Default::default()
23349    };
23350
23351    let mut prev_end = label.filter_range.end;
23352    label
23353        .runs
23354        .iter()
23355        .enumerate()
23356        .flat_map(move |(ix, (range, highlight_id))| {
23357            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23358                style
23359            } else {
23360                return Default::default();
23361            };
23362            let mut muted_style = style;
23363            muted_style.highlight(fade_out);
23364
23365            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23366            if range.start >= label.filter_range.end {
23367                if range.start > prev_end {
23368                    runs.push((prev_end..range.start, fade_out));
23369                }
23370                runs.push((range.clone(), muted_style));
23371            } else if range.end <= label.filter_range.end {
23372                runs.push((range.clone(), style));
23373            } else {
23374                runs.push((range.start..label.filter_range.end, style));
23375                runs.push((label.filter_range.end..range.end, muted_style));
23376            }
23377            prev_end = cmp::max(prev_end, range.end);
23378
23379            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23380                runs.push((prev_end..label.text.len(), fade_out));
23381            }
23382
23383            runs
23384        })
23385}
23386
23387pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23388    let mut prev_index = 0;
23389    let mut prev_codepoint: Option<char> = None;
23390    text.char_indices()
23391        .chain([(text.len(), '\0')])
23392        .filter_map(move |(index, codepoint)| {
23393            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23394            let is_boundary = index == text.len()
23395                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23396                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23397            if is_boundary {
23398                let chunk = &text[prev_index..index];
23399                prev_index = index;
23400                Some(chunk)
23401            } else {
23402                None
23403            }
23404        })
23405}
23406
23407pub trait RangeToAnchorExt: Sized {
23408    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23409
23410    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23411        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23412        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23413    }
23414}
23415
23416impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23417    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23418        let start_offset = self.start.to_offset(snapshot);
23419        let end_offset = self.end.to_offset(snapshot);
23420        if start_offset == end_offset {
23421            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23422        } else {
23423            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23424        }
23425    }
23426}
23427
23428pub trait RowExt {
23429    fn as_f32(&self) -> f32;
23430
23431    fn next_row(&self) -> Self;
23432
23433    fn previous_row(&self) -> Self;
23434
23435    fn minus(&self, other: Self) -> u32;
23436}
23437
23438impl RowExt for DisplayRow {
23439    fn as_f32(&self) -> f32 {
23440        self.0 as f32
23441    }
23442
23443    fn next_row(&self) -> Self {
23444        Self(self.0 + 1)
23445    }
23446
23447    fn previous_row(&self) -> Self {
23448        Self(self.0.saturating_sub(1))
23449    }
23450
23451    fn minus(&self, other: Self) -> u32 {
23452        self.0 - other.0
23453    }
23454}
23455
23456impl RowExt for MultiBufferRow {
23457    fn as_f32(&self) -> f32 {
23458        self.0 as f32
23459    }
23460
23461    fn next_row(&self) -> Self {
23462        Self(self.0 + 1)
23463    }
23464
23465    fn previous_row(&self) -> Self {
23466        Self(self.0.saturating_sub(1))
23467    }
23468
23469    fn minus(&self, other: Self) -> u32 {
23470        self.0 - other.0
23471    }
23472}
23473
23474trait RowRangeExt {
23475    type Row;
23476
23477    fn len(&self) -> usize;
23478
23479    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23480}
23481
23482impl RowRangeExt for Range<MultiBufferRow> {
23483    type Row = MultiBufferRow;
23484
23485    fn len(&self) -> usize {
23486        (self.end.0 - self.start.0) as usize
23487    }
23488
23489    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23490        (self.start.0..self.end.0).map(MultiBufferRow)
23491    }
23492}
23493
23494impl RowRangeExt for Range<DisplayRow> {
23495    type Row = DisplayRow;
23496
23497    fn len(&self) -> usize {
23498        (self.end.0 - self.start.0) as usize
23499    }
23500
23501    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23502        (self.start.0..self.end.0).map(DisplayRow)
23503    }
23504}
23505
23506/// If select range has more than one line, we
23507/// just point the cursor to range.start.
23508fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23509    if range.start.row == range.end.row {
23510        range
23511    } else {
23512        range.start..range.start
23513    }
23514}
23515pub struct KillRing(ClipboardItem);
23516impl Global for KillRing {}
23517
23518const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23519
23520enum BreakpointPromptEditAction {
23521    Log,
23522    Condition,
23523    HitCondition,
23524}
23525
23526struct BreakpointPromptEditor {
23527    pub(crate) prompt: Entity<Editor>,
23528    editor: WeakEntity<Editor>,
23529    breakpoint_anchor: Anchor,
23530    breakpoint: Breakpoint,
23531    edit_action: BreakpointPromptEditAction,
23532    block_ids: HashSet<CustomBlockId>,
23533    editor_margins: Arc<Mutex<EditorMargins>>,
23534    _subscriptions: Vec<Subscription>,
23535}
23536
23537impl BreakpointPromptEditor {
23538    const MAX_LINES: u8 = 4;
23539
23540    fn new(
23541        editor: WeakEntity<Editor>,
23542        breakpoint_anchor: Anchor,
23543        breakpoint: Breakpoint,
23544        edit_action: BreakpointPromptEditAction,
23545        window: &mut Window,
23546        cx: &mut Context<Self>,
23547    ) -> Self {
23548        let base_text = match edit_action {
23549            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23550            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23551            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23552        }
23553        .map(|msg| msg.to_string())
23554        .unwrap_or_default();
23555
23556        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23557        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23558
23559        let prompt = cx.new(|cx| {
23560            let mut prompt = Editor::new(
23561                EditorMode::AutoHeight {
23562                    min_lines: 1,
23563                    max_lines: Some(Self::MAX_LINES as usize),
23564                },
23565                buffer,
23566                None,
23567                window,
23568                cx,
23569            );
23570            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23571            prompt.set_show_cursor_when_unfocused(false, cx);
23572            prompt.set_placeholder_text(
23573                match edit_action {
23574                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23575                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23576                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23577                },
23578                cx,
23579            );
23580
23581            prompt
23582        });
23583
23584        Self {
23585            prompt,
23586            editor,
23587            breakpoint_anchor,
23588            breakpoint,
23589            edit_action,
23590            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23591            block_ids: Default::default(),
23592            _subscriptions: vec![],
23593        }
23594    }
23595
23596    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23597        self.block_ids.extend(block_ids)
23598    }
23599
23600    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23601        if let Some(editor) = self.editor.upgrade() {
23602            let message = self
23603                .prompt
23604                .read(cx)
23605                .buffer
23606                .read(cx)
23607                .as_singleton()
23608                .expect("A multi buffer in breakpoint prompt isn't possible")
23609                .read(cx)
23610                .as_rope()
23611                .to_string();
23612
23613            editor.update(cx, |editor, cx| {
23614                editor.edit_breakpoint_at_anchor(
23615                    self.breakpoint_anchor,
23616                    self.breakpoint.clone(),
23617                    match self.edit_action {
23618                        BreakpointPromptEditAction::Log => {
23619                            BreakpointEditAction::EditLogMessage(message.into())
23620                        }
23621                        BreakpointPromptEditAction::Condition => {
23622                            BreakpointEditAction::EditCondition(message.into())
23623                        }
23624                        BreakpointPromptEditAction::HitCondition => {
23625                            BreakpointEditAction::EditHitCondition(message.into())
23626                        }
23627                    },
23628                    cx,
23629                );
23630
23631                editor.remove_blocks(self.block_ids.clone(), None, cx);
23632                cx.focus_self(window);
23633            });
23634        }
23635    }
23636
23637    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23638        self.editor
23639            .update(cx, |editor, cx| {
23640                editor.remove_blocks(self.block_ids.clone(), None, cx);
23641                window.focus(&editor.focus_handle);
23642            })
23643            .log_err();
23644    }
23645
23646    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23647        let settings = ThemeSettings::get_global(cx);
23648        let text_style = TextStyle {
23649            color: if self.prompt.read(cx).read_only(cx) {
23650                cx.theme().colors().text_disabled
23651            } else {
23652                cx.theme().colors().text
23653            },
23654            font_family: settings.buffer_font.family.clone(),
23655            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23656            font_size: settings.buffer_font_size(cx).into(),
23657            font_weight: settings.buffer_font.weight,
23658            line_height: relative(settings.buffer_line_height.value()),
23659            ..Default::default()
23660        };
23661        EditorElement::new(
23662            &self.prompt,
23663            EditorStyle {
23664                background: cx.theme().colors().editor_background,
23665                local_player: cx.theme().players().local(),
23666                text: text_style,
23667                ..Default::default()
23668            },
23669        )
23670    }
23671}
23672
23673impl Render for BreakpointPromptEditor {
23674    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23675        let editor_margins = *self.editor_margins.lock();
23676        let gutter_dimensions = editor_margins.gutter;
23677        h_flex()
23678            .key_context("Editor")
23679            .bg(cx.theme().colors().editor_background)
23680            .border_y_1()
23681            .border_color(cx.theme().status().info_border)
23682            .size_full()
23683            .py(window.line_height() / 2.5)
23684            .on_action(cx.listener(Self::confirm))
23685            .on_action(cx.listener(Self::cancel))
23686            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23687            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23688    }
23689}
23690
23691impl Focusable for BreakpointPromptEditor {
23692    fn focus_handle(&self, cx: &App) -> FocusHandle {
23693        self.prompt.focus_handle(cx)
23694    }
23695}
23696
23697fn all_edits_insertions_or_deletions(
23698    edits: &Vec<(Range<Anchor>, String)>,
23699    snapshot: &MultiBufferSnapshot,
23700) -> bool {
23701    let mut all_insertions = true;
23702    let mut all_deletions = true;
23703
23704    for (range, new_text) in edits.iter() {
23705        let range_is_empty = range.to_offset(&snapshot).is_empty();
23706        let text_is_empty = new_text.is_empty();
23707
23708        if range_is_empty != text_is_empty {
23709            if range_is_empty {
23710                all_deletions = false;
23711            } else {
23712                all_insertions = false;
23713            }
23714        } else {
23715            return false;
23716        }
23717
23718        if !all_insertions && !all_deletions {
23719            return false;
23720        }
23721    }
23722    all_insertions || all_deletions
23723}
23724
23725struct MissingEditPredictionKeybindingTooltip;
23726
23727impl Render for MissingEditPredictionKeybindingTooltip {
23728    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23729        ui::tooltip_container(window, cx, |container, _, cx| {
23730            container
23731                .flex_shrink_0()
23732                .max_w_80()
23733                .min_h(rems_from_px(124.))
23734                .justify_between()
23735                .child(
23736                    v_flex()
23737                        .flex_1()
23738                        .text_ui_sm(cx)
23739                        .child(Label::new("Conflict with Accept Keybinding"))
23740                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23741                )
23742                .child(
23743                    h_flex()
23744                        .pb_1()
23745                        .gap_1()
23746                        .items_end()
23747                        .w_full()
23748                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23749                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23750                        }))
23751                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23752                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23753                        })),
23754                )
23755        })
23756    }
23757}
23758
23759#[derive(Debug, Clone, Copy, PartialEq)]
23760pub struct LineHighlight {
23761    pub background: Background,
23762    pub border: Option<gpui::Hsla>,
23763    pub include_gutter: bool,
23764    pub type_id: Option<TypeId>,
23765}
23766
23767struct LineManipulationResult {
23768    pub new_text: String,
23769    pub line_count_before: usize,
23770    pub line_count_after: usize,
23771}
23772
23773fn render_diff_hunk_controls(
23774    row: u32,
23775    status: &DiffHunkStatus,
23776    hunk_range: Range<Anchor>,
23777    is_created_file: bool,
23778    line_height: Pixels,
23779    editor: &Entity<Editor>,
23780    _window: &mut Window,
23781    cx: &mut App,
23782) -> AnyElement {
23783    h_flex()
23784        .h(line_height)
23785        .mr_1()
23786        .gap_1()
23787        .px_0p5()
23788        .pb_1()
23789        .border_x_1()
23790        .border_b_1()
23791        .border_color(cx.theme().colors().border_variant)
23792        .rounded_b_lg()
23793        .bg(cx.theme().colors().editor_background)
23794        .gap_1()
23795        .block_mouse_except_scroll()
23796        .shadow_md()
23797        .child(if status.has_secondary_hunk() {
23798            Button::new(("stage", row as u64), "Stage")
23799                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23800                .tooltip({
23801                    let focus_handle = editor.focus_handle(cx);
23802                    move |window, cx| {
23803                        Tooltip::for_action_in(
23804                            "Stage Hunk",
23805                            &::git::ToggleStaged,
23806                            &focus_handle,
23807                            window,
23808                            cx,
23809                        )
23810                    }
23811                })
23812                .on_click({
23813                    let editor = editor.clone();
23814                    move |_event, _window, cx| {
23815                        editor.update(cx, |editor, cx| {
23816                            editor.stage_or_unstage_diff_hunks(
23817                                true,
23818                                vec![hunk_range.start..hunk_range.start],
23819                                cx,
23820                            );
23821                        });
23822                    }
23823                })
23824        } else {
23825            Button::new(("unstage", row as u64), "Unstage")
23826                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23827                .tooltip({
23828                    let focus_handle = editor.focus_handle(cx);
23829                    move |window, cx| {
23830                        Tooltip::for_action_in(
23831                            "Unstage Hunk",
23832                            &::git::ToggleStaged,
23833                            &focus_handle,
23834                            window,
23835                            cx,
23836                        )
23837                    }
23838                })
23839                .on_click({
23840                    let editor = editor.clone();
23841                    move |_event, _window, cx| {
23842                        editor.update(cx, |editor, cx| {
23843                            editor.stage_or_unstage_diff_hunks(
23844                                false,
23845                                vec![hunk_range.start..hunk_range.start],
23846                                cx,
23847                            );
23848                        });
23849                    }
23850                })
23851        })
23852        .child(
23853            Button::new(("restore", row as u64), "Restore")
23854                .tooltip({
23855                    let focus_handle = editor.focus_handle(cx);
23856                    move |window, cx| {
23857                        Tooltip::for_action_in(
23858                            "Restore Hunk",
23859                            &::git::Restore,
23860                            &focus_handle,
23861                            window,
23862                            cx,
23863                        )
23864                    }
23865                })
23866                .on_click({
23867                    let editor = editor.clone();
23868                    move |_event, window, cx| {
23869                        editor.update(cx, |editor, cx| {
23870                            let snapshot = editor.snapshot(window, cx);
23871                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23872                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23873                        });
23874                    }
23875                })
23876                .disabled(is_created_file),
23877        )
23878        .when(
23879            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23880            |el| {
23881                el.child(
23882                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23883                        .shape(IconButtonShape::Square)
23884                        .icon_size(IconSize::Small)
23885                        // .disabled(!has_multiple_hunks)
23886                        .tooltip({
23887                            let focus_handle = editor.focus_handle(cx);
23888                            move |window, cx| {
23889                                Tooltip::for_action_in(
23890                                    "Next Hunk",
23891                                    &GoToHunk,
23892                                    &focus_handle,
23893                                    window,
23894                                    cx,
23895                                )
23896                            }
23897                        })
23898                        .on_click({
23899                            let editor = editor.clone();
23900                            move |_event, window, cx| {
23901                                editor.update(cx, |editor, cx| {
23902                                    let snapshot = editor.snapshot(window, cx);
23903                                    let position =
23904                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23905                                    editor.go_to_hunk_before_or_after_position(
23906                                        &snapshot,
23907                                        position,
23908                                        Direction::Next,
23909                                        window,
23910                                        cx,
23911                                    );
23912                                    editor.expand_selected_diff_hunks(cx);
23913                                });
23914                            }
23915                        }),
23916                )
23917                .child(
23918                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23919                        .shape(IconButtonShape::Square)
23920                        .icon_size(IconSize::Small)
23921                        // .disabled(!has_multiple_hunks)
23922                        .tooltip({
23923                            let focus_handle = editor.focus_handle(cx);
23924                            move |window, cx| {
23925                                Tooltip::for_action_in(
23926                                    "Previous Hunk",
23927                                    &GoToPreviousHunk,
23928                                    &focus_handle,
23929                                    window,
23930                                    cx,
23931                                )
23932                            }
23933                        })
23934                        .on_click({
23935                            let editor = editor.clone();
23936                            move |_event, window, cx| {
23937                                editor.update(cx, |editor, cx| {
23938                                    let snapshot = editor.snapshot(window, cx);
23939                                    let point =
23940                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23941                                    editor.go_to_hunk_before_or_after_position(
23942                                        &snapshot,
23943                                        point,
23944                                        Direction::Prev,
23945                                        window,
23946                                        cx,
23947                                    );
23948                                    editor.expand_selected_diff_hunks(cx);
23949                                });
23950                            }
23951                        }),
23952                )
23953            },
23954        )
23955        .into_any_element()
23956}