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 editor_tests;
   47#[cfg(test)]
   48mod inline_completion_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 editor_settings::{
   56    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   57    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap, ShowScrollbar,
   58};
   59pub use editor_settings_controls::*;
   60pub use element::{
   61    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   62};
   63pub use git::blame::BlameRenderer;
   64pub use hover_popover::hover_markdown_style;
   65pub use inline_completion::Direction;
   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, DisableAiSettings, 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 editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   97use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   98use futures::{
   99    FutureExt, StreamExt as _,
  100    future::{self, Shared, join},
  101    stream::FuturesUnordered,
  102};
  103use fuzzy::{StringMatch, StringMatchCandidate};
  104use git::blame::{GitBlame, GlobalBlameRenderer};
  105use gpui::{
  106    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  107    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  108    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  109    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  110    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  111    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  112    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  113    div, point, prelude::*, pulsating_between, px, relative, size,
  114};
  115use highlight_matching_bracket::refresh_matching_bracket_highlights;
  116use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  117use hover_popover::{HoverState, hide_hover};
  118use indent_guides::ActiveIndentGuidesState;
  119use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  120use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  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, LanguageServerName,
  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, DocumentHighlight, InlayHint, Location, LocationLink, PrepareRenameResponse,
  152    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    InlineCompletion(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::InlineCompletion(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 inline_completion_styles: InlineCompletionStyles,
  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            inline_completion_styles: InlineCompletionStyles {
  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) -> InlineCompletionStyles {
  592    InlineCompletionStyles {
  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 InlineCompletion {
  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 InlineCompletionState {
  626    inlay_ids: Vec<InlayId>,
  627    completion: InlineCompletion,
  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 InlineCompletionHighlight {}
  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 MenuInlineCompletionsPolicy {
  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<RegisteredInlineCompletionProvider>,
 1091    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1092    active_inline_completion: Option<InlineCompletionState>,
 1093    /// Used to prevent flickering as the user types while the menu is open
 1094    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1095    edit_prediction_settings: EditPredictionSettings,
 1096    inline_completions_hidden_for_vim_mode: bool,
 1097    show_inline_completions_override: Option<bool>,
 1098    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 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 RegisteredInlineCompletionProvider {
 1514    provider: Arc<dyn InlineCompletionProviderHandle>,
 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                            editor.update_lsp_data(true, None, window, cx);
 1868                        }
 1869                        project::Event::SnippetEdit(id, snippet_edits) => {
 1870                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1871                                let focus_handle = editor.focus_handle(cx);
 1872                                if focus_handle.is_focused(window) {
 1873                                    let snapshot = buffer.read(cx).snapshot();
 1874                                    for (range, snippet) in snippet_edits {
 1875                                        let editor_range =
 1876                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1877                                        editor
 1878                                            .insert_snippet(
 1879                                                &[editor_range],
 1880                                                snippet.clone(),
 1881                                                window,
 1882                                                cx,
 1883                                            )
 1884                                            .ok();
 1885                                    }
 1886                                }
 1887                            }
 1888                        }
 1889                        _ => {}
 1890                    },
 1891                ));
 1892                if let Some(task_inventory) = project
 1893                    .read(cx)
 1894                    .task_store()
 1895                    .read(cx)
 1896                    .task_inventory()
 1897                    .cloned()
 1898                {
 1899                    project_subscriptions.push(cx.observe_in(
 1900                        &task_inventory,
 1901                        window,
 1902                        |editor, _, window, cx| {
 1903                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1904                        },
 1905                    ));
 1906                };
 1907
 1908                project_subscriptions.push(cx.subscribe_in(
 1909                    &project.read(cx).breakpoint_store(),
 1910                    window,
 1911                    |editor, _, event, window, cx| match event {
 1912                        BreakpointStoreEvent::ClearDebugLines => {
 1913                            editor.clear_row_highlights::<ActiveDebugLine>();
 1914                            editor.refresh_inline_values(cx);
 1915                        }
 1916                        BreakpointStoreEvent::SetDebugLine => {
 1917                            if editor.go_to_active_debug_line(window, cx) {
 1918                                cx.stop_propagation();
 1919                            }
 1920
 1921                            editor.refresh_inline_values(cx);
 1922                        }
 1923                        _ => {}
 1924                    },
 1925                ));
 1926                let git_store = project.read(cx).git_store().clone();
 1927                let project = project.clone();
 1928                project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1929                    match event {
 1930                        GitStoreEvent::RepositoryUpdated(
 1931                            _,
 1932                            RepositoryEvent::Updated {
 1933                                new_instance: true, ..
 1934                            },
 1935                            _,
 1936                        ) => {
 1937                            this.load_diff_task = Some(
 1938                                update_uncommitted_diff_for_buffer(
 1939                                    cx.entity(),
 1940                                    &project,
 1941                                    this.buffer.read(cx).all_buffers(),
 1942                                    this.buffer.clone(),
 1943                                    cx,
 1944                                )
 1945                                .shared(),
 1946                            );
 1947                        }
 1948                        _ => {}
 1949                    }
 1950                }));
 1951            }
 1952        }
 1953
 1954        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1955
 1956        let inlay_hint_settings =
 1957            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1958        let focus_handle = cx.focus_handle();
 1959        if !is_minimap {
 1960            cx.on_focus(&focus_handle, window, Self::handle_focus)
 1961                .detach();
 1962            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1963                .detach();
 1964            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1965                .detach();
 1966            cx.on_blur(&focus_handle, window, Self::handle_blur)
 1967                .detach();
 1968            cx.observe_pending_input(window, Self::observe_pending_input)
 1969                .detach();
 1970        }
 1971
 1972        let show_indent_guides = if matches!(
 1973            mode,
 1974            EditorMode::SingleLine { .. } | EditorMode::Minimap { .. }
 1975        ) {
 1976            Some(false)
 1977        } else {
 1978            None
 1979        };
 1980
 1981        let breakpoint_store = match (&mode, project.as_ref()) {
 1982            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1983            _ => None,
 1984        };
 1985
 1986        let mut code_action_providers = Vec::new();
 1987        let mut load_uncommitted_diff = None;
 1988        if let Some(project) = project.clone() {
 1989            load_uncommitted_diff = Some(
 1990                update_uncommitted_diff_for_buffer(
 1991                    cx.entity(),
 1992                    &project,
 1993                    buffer.read(cx).all_buffers(),
 1994                    buffer.clone(),
 1995                    cx,
 1996                )
 1997                .shared(),
 1998            );
 1999            code_action_providers.push(Rc::new(project) as Rc<_>);
 2000        }
 2001
 2002        let mut editor = Self {
 2003            focus_handle,
 2004            show_cursor_when_unfocused: false,
 2005            last_focused_descendant: None,
 2006            buffer: buffer.clone(),
 2007            display_map: display_map.clone(),
 2008            selections,
 2009            scroll_manager: ScrollManager::new(cx),
 2010            columnar_selection_state: None,
 2011            add_selections_state: None,
 2012            select_next_state: None,
 2013            select_prev_state: None,
 2014            selection_history: SelectionHistory::default(),
 2015            defer_selection_effects: false,
 2016            deferred_selection_effects_state: None,
 2017            autoclose_regions: Vec::new(),
 2018            snippet_stack: InvalidationStack::default(),
 2019            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2020            ime_transaction: None,
 2021            active_diagnostics: ActiveDiagnostic::None,
 2022            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2023            inline_diagnostics_update: Task::ready(()),
 2024            inline_diagnostics: Vec::new(),
 2025            soft_wrap_mode_override,
 2026            diagnostics_max_severity,
 2027            hard_wrap: None,
 2028            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2029            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2030            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2031            project,
 2032            blink_manager: blink_manager.clone(),
 2033            show_local_selections: true,
 2034            show_scrollbars: ScrollbarAxes {
 2035                horizontal: full_mode,
 2036                vertical: full_mode,
 2037            },
 2038            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2039            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 2040            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2041            show_gutter: full_mode,
 2042            show_line_numbers: (!full_mode).then_some(false),
 2043            use_relative_line_numbers: None,
 2044            disable_expand_excerpt_buttons: !full_mode,
 2045            show_git_diff_gutter: None,
 2046            show_code_actions: None,
 2047            show_runnables: None,
 2048            show_breakpoints: None,
 2049            show_wrap_guides: None,
 2050            show_indent_guides,
 2051            placeholder_text: None,
 2052            highlight_order: 0,
 2053            highlighted_rows: HashMap::default(),
 2054            background_highlights: TreeMap::default(),
 2055            gutter_highlights: TreeMap::default(),
 2056            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2057            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2058            nav_history: None,
 2059            context_menu: RefCell::new(None),
 2060            context_menu_options: None,
 2061            mouse_context_menu: None,
 2062            completion_tasks: Vec::new(),
 2063            inline_blame_popover: None,
 2064            inline_blame_popover_show_task: None,
 2065            signature_help_state: SignatureHelpState::default(),
 2066            auto_signature_help: None,
 2067            find_all_references_task_sources: Vec::new(),
 2068            next_completion_id: 0,
 2069            next_inlay_id: 0,
 2070            code_action_providers,
 2071            available_code_actions: None,
 2072            code_actions_task: None,
 2073            quick_selection_highlight_task: None,
 2074            debounced_selection_highlight_task: None,
 2075            document_highlights_task: None,
 2076            linked_editing_range_task: None,
 2077            pending_rename: None,
 2078            searchable: !is_minimap,
 2079            cursor_shape: EditorSettings::get_global(cx)
 2080                .cursor_shape
 2081                .unwrap_or_default(),
 2082            current_line_highlight: None,
 2083            autoindent_mode: Some(AutoindentMode::EachLine),
 2084            collapse_matches: false,
 2085            workspace: None,
 2086            input_enabled: !is_minimap,
 2087            use_modal_editing: full_mode,
 2088            read_only: is_minimap,
 2089            use_autoclose: true,
 2090            use_auto_surround: true,
 2091            auto_replace_emoji_shortcode: false,
 2092            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2093            leader_id: None,
 2094            remote_id: None,
 2095            hover_state: HoverState::default(),
 2096            pending_mouse_down: None,
 2097            hovered_link_state: None,
 2098            edit_prediction_provider: None,
 2099            active_inline_completion: None,
 2100            stale_inline_completion_in_menu: None,
 2101            edit_prediction_preview: EditPredictionPreview::Inactive {
 2102                released_too_fast: false,
 2103            },
 2104            inline_diagnostics_enabled: full_mode,
 2105            diagnostics_enabled: full_mode,
 2106            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2107            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2108            gutter_hovered: false,
 2109            pixel_position_of_newest_cursor: None,
 2110            last_bounds: None,
 2111            last_position_map: None,
 2112            expect_bounds_change: None,
 2113            gutter_dimensions: GutterDimensions::default(),
 2114            style: None,
 2115            show_cursor_names: false,
 2116            hovered_cursors: HashMap::default(),
 2117            next_editor_action_id: EditorActionId::default(),
 2118            editor_actions: Rc::default(),
 2119            inline_completions_hidden_for_vim_mode: false,
 2120            show_inline_completions_override: None,
 2121            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 2122            edit_prediction_settings: EditPredictionSettings::Disabled,
 2123            edit_prediction_indent_conflict: false,
 2124            edit_prediction_requires_modifier_in_indent_conflict: true,
 2125            custom_context_menu: None,
 2126            show_git_blame_gutter: false,
 2127            show_git_blame_inline: false,
 2128            show_selection_menu: None,
 2129            show_git_blame_inline_delay_task: None,
 2130            git_blame_inline_enabled: full_mode
 2131                && ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2132            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2133            serialize_dirty_buffers: !is_minimap
 2134                && ProjectSettings::get_global(cx)
 2135                    .session
 2136                    .restore_unsaved_buffers,
 2137            blame: None,
 2138            blame_subscription: None,
 2139            tasks: BTreeMap::default(),
 2140
 2141            breakpoint_store,
 2142            gutter_breakpoint_indicator: (None, None),
 2143            hovered_diff_hunk_row: None,
 2144            _subscriptions: (!is_minimap)
 2145                .then(|| {
 2146                    vec![
 2147                        cx.observe(&buffer, Self::on_buffer_changed),
 2148                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2149                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2150                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2151                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2152                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2153                        cx.observe_window_activation(window, |editor, window, cx| {
 2154                            let active = window.is_window_active();
 2155                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2156                                if active {
 2157                                    blink_manager.enable(cx);
 2158                                } else {
 2159                                    blink_manager.disable(cx);
 2160                                }
 2161                            });
 2162                            if active {
 2163                                editor.show_mouse_cursor(cx);
 2164                            }
 2165                        }),
 2166                    ]
 2167                })
 2168                .unwrap_or_default(),
 2169            tasks_update_task: None,
 2170            pull_diagnostics_task: Task::ready(()),
 2171            colors: None,
 2172            next_color_inlay_id: 0,
 2173            linked_edit_ranges: Default::default(),
 2174            in_project_search: false,
 2175            previous_search_ranges: None,
 2176            breadcrumb_header: None,
 2177            focused_block: None,
 2178            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2179            addons: HashMap::default(),
 2180            registered_buffers: HashMap::default(),
 2181            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2182            selection_mark_mode: false,
 2183            toggle_fold_multiple_buffers: Task::ready(()),
 2184            serialize_selections: Task::ready(()),
 2185            serialize_folds: Task::ready(()),
 2186            text_style_refinement: None,
 2187            load_diff_task: load_uncommitted_diff,
 2188            temporary_diff_override: false,
 2189            mouse_cursor_hidden: false,
 2190            minimap: None,
 2191            hide_mouse_mode: EditorSettings::get_global(cx)
 2192                .hide_mouse
 2193                .unwrap_or_default(),
 2194            change_list: ChangeList::new(),
 2195            mode,
 2196            selection_drag_state: SelectionDragState::None,
 2197            folding_newlines: Task::ready(()),
 2198        };
 2199
 2200        if is_minimap {
 2201            return editor;
 2202        }
 2203
 2204        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2205            editor
 2206                ._subscriptions
 2207                .push(cx.observe(breakpoints, |_, _, cx| {
 2208                    cx.notify();
 2209                }));
 2210        }
 2211        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2212        editor._subscriptions.extend(project_subscriptions);
 2213
 2214        editor._subscriptions.push(cx.subscribe_in(
 2215            &cx.entity(),
 2216            window,
 2217            |editor, _, e: &EditorEvent, window, cx| match e {
 2218                EditorEvent::ScrollPositionChanged { local, .. } => {
 2219                    if *local {
 2220                        let new_anchor = editor.scroll_manager.anchor();
 2221                        let snapshot = editor.snapshot(window, cx);
 2222                        editor.update_restoration_data(cx, move |data| {
 2223                            data.scroll_position = (
 2224                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2225                                new_anchor.offset,
 2226                            );
 2227                        });
 2228                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2229                        editor.inline_blame_popover.take();
 2230                    }
 2231                }
 2232                EditorEvent::Edited { .. } => {
 2233                    if !vim_enabled(cx) {
 2234                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2235                        let pop_state = editor
 2236                            .change_list
 2237                            .last()
 2238                            .map(|previous| {
 2239                                previous.len() == selections.len()
 2240                                    && previous.iter().enumerate().all(|(ix, p)| {
 2241                                        p.to_display_point(&map).row()
 2242                                            == selections[ix].head().row()
 2243                                    })
 2244                            })
 2245                            .unwrap_or(false);
 2246                        let new_positions = selections
 2247                            .into_iter()
 2248                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2249                            .collect();
 2250                        editor
 2251                            .change_list
 2252                            .push_to_change_list(pop_state, new_positions);
 2253                    }
 2254                }
 2255                _ => (),
 2256            },
 2257        ));
 2258
 2259        if let Some(dap_store) = editor
 2260            .project
 2261            .as_ref()
 2262            .map(|project| project.read(cx).dap_store())
 2263        {
 2264            let weak_editor = cx.weak_entity();
 2265
 2266            editor
 2267                ._subscriptions
 2268                .push(
 2269                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2270                        let session_entity = cx.entity();
 2271                        weak_editor
 2272                            .update(cx, |editor, cx| {
 2273                                editor._subscriptions.push(
 2274                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2275                                );
 2276                            })
 2277                            .ok();
 2278                    }),
 2279                );
 2280
 2281            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2282                editor
 2283                    ._subscriptions
 2284                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2285            }
 2286        }
 2287
 2288        // skip adding the initial selection to selection history
 2289        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2290        editor.end_selection(window, cx);
 2291        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2292
 2293        editor.scroll_manager.show_scrollbars(window, cx);
 2294        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2295
 2296        if full_mode {
 2297            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2298            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2299
 2300            if editor.git_blame_inline_enabled {
 2301                editor.start_git_blame_inline(false, window, cx);
 2302            }
 2303
 2304            editor.go_to_active_debug_line(window, cx);
 2305
 2306            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2307                if let Some(project) = editor.project.as_ref() {
 2308                    let handle = project.update(cx, |project, cx| {
 2309                        project.register_buffer_with_language_servers(&buffer, cx)
 2310                    });
 2311                    editor
 2312                        .registered_buffers
 2313                        .insert(buffer.read(cx).remote_id(), handle);
 2314                }
 2315            }
 2316
 2317            editor.minimap =
 2318                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2319            editor.colors = Some(LspColorData::new(cx));
 2320            editor.update_lsp_data(false, None, window, cx);
 2321        }
 2322
 2323        if editor.mode.is_full() {
 2324            editor.report_editor_event("Editor Opened", None, cx);
 2325        }
 2326
 2327        editor
 2328    }
 2329
 2330    pub fn deploy_mouse_context_menu(
 2331        &mut self,
 2332        position: gpui::Point<Pixels>,
 2333        context_menu: Entity<ContextMenu>,
 2334        window: &mut Window,
 2335        cx: &mut Context<Self>,
 2336    ) {
 2337        self.mouse_context_menu = Some(MouseContextMenu::new(
 2338            self,
 2339            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2340            context_menu,
 2341            window,
 2342            cx,
 2343        ));
 2344    }
 2345
 2346    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2347        self.mouse_context_menu
 2348            .as_ref()
 2349            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2350    }
 2351
 2352    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2353        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2354    }
 2355
 2356    fn key_context_internal(
 2357        &self,
 2358        has_active_edit_prediction: bool,
 2359        window: &Window,
 2360        cx: &App,
 2361    ) -> KeyContext {
 2362        let mut key_context = KeyContext::new_with_defaults();
 2363        key_context.add("Editor");
 2364        let mode = match self.mode {
 2365            EditorMode::SingleLine { .. } => "single_line",
 2366            EditorMode::AutoHeight { .. } => "auto_height",
 2367            EditorMode::Minimap { .. } => "minimap",
 2368            EditorMode::Full { .. } => "full",
 2369        };
 2370
 2371        if EditorSettings::jupyter_enabled(cx) {
 2372            key_context.add("jupyter");
 2373        }
 2374
 2375        key_context.set("mode", mode);
 2376        if self.pending_rename.is_some() {
 2377            key_context.add("renaming");
 2378        }
 2379
 2380        match self.context_menu.borrow().as_ref() {
 2381            Some(CodeContextMenu::Completions(menu)) => {
 2382                if menu.visible() {
 2383                    key_context.add("menu");
 2384                    key_context.add("showing_completions");
 2385                }
 2386            }
 2387            Some(CodeContextMenu::CodeActions(menu)) => {
 2388                if menu.visible() {
 2389                    key_context.add("menu");
 2390                    key_context.add("showing_code_actions")
 2391                }
 2392            }
 2393            None => {}
 2394        }
 2395
 2396        if self.signature_help_state.has_multiple_signatures() {
 2397            key_context.add("showing_signature_help");
 2398        }
 2399
 2400        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2401        if !self.focus_handle(cx).contains_focused(window, cx)
 2402            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2403        {
 2404            for addon in self.addons.values() {
 2405                addon.extend_key_context(&mut key_context, cx)
 2406            }
 2407        }
 2408
 2409        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2410            if let Some(extension) = singleton_buffer
 2411                .read(cx)
 2412                .file()
 2413                .and_then(|file| file.path().extension()?.to_str())
 2414            {
 2415                key_context.set("extension", extension.to_string());
 2416            }
 2417        } else {
 2418            key_context.add("multibuffer");
 2419        }
 2420
 2421        if has_active_edit_prediction {
 2422            if self.edit_prediction_in_conflict() {
 2423                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2424            } else {
 2425                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2426                key_context.add("copilot_suggestion");
 2427            }
 2428        }
 2429
 2430        if self.selection_mark_mode {
 2431            key_context.add("selection_mode");
 2432        }
 2433
 2434        key_context
 2435    }
 2436
 2437    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2438        if self.mouse_cursor_hidden {
 2439            self.mouse_cursor_hidden = false;
 2440            cx.notify();
 2441        }
 2442    }
 2443
 2444    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2445        let hide_mouse_cursor = match origin {
 2446            HideMouseCursorOrigin::TypingAction => {
 2447                matches!(
 2448                    self.hide_mouse_mode,
 2449                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2450                )
 2451            }
 2452            HideMouseCursorOrigin::MovementAction => {
 2453                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2454            }
 2455        };
 2456        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2457            self.mouse_cursor_hidden = hide_mouse_cursor;
 2458            cx.notify();
 2459        }
 2460    }
 2461
 2462    pub fn edit_prediction_in_conflict(&self) -> bool {
 2463        if !self.show_edit_predictions_in_menu() {
 2464            return false;
 2465        }
 2466
 2467        let showing_completions = self
 2468            .context_menu
 2469            .borrow()
 2470            .as_ref()
 2471            .map_or(false, |context| {
 2472                matches!(context, CodeContextMenu::Completions(_))
 2473            });
 2474
 2475        showing_completions
 2476            || self.edit_prediction_requires_modifier()
 2477            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2478            // bindings to insert tab characters.
 2479            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2480    }
 2481
 2482    pub fn accept_edit_prediction_keybind(
 2483        &self,
 2484        accept_partial: bool,
 2485        window: &Window,
 2486        cx: &App,
 2487    ) -> AcceptEditPredictionBinding {
 2488        let key_context = self.key_context_internal(true, window, cx);
 2489        let in_conflict = self.edit_prediction_in_conflict();
 2490
 2491        let bindings = if accept_partial {
 2492            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2493        } else {
 2494            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2495        };
 2496
 2497        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2498        // just the first one.
 2499        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2500            !in_conflict
 2501                || binding
 2502                    .keystrokes()
 2503                    .first()
 2504                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2505        }))
 2506    }
 2507
 2508    pub fn new_file(
 2509        workspace: &mut Workspace,
 2510        _: &workspace::NewFile,
 2511        window: &mut Window,
 2512        cx: &mut Context<Workspace>,
 2513    ) {
 2514        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2515            "Failed to create buffer",
 2516            window,
 2517            cx,
 2518            |e, _, _| match e.error_code() {
 2519                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2520                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2521                e.error_tag("required").unwrap_or("the latest version")
 2522            )),
 2523                _ => None,
 2524            },
 2525        );
 2526    }
 2527
 2528    pub fn new_in_workspace(
 2529        workspace: &mut Workspace,
 2530        window: &mut Window,
 2531        cx: &mut Context<Workspace>,
 2532    ) -> Task<Result<Entity<Editor>>> {
 2533        let project = workspace.project().clone();
 2534        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2535
 2536        cx.spawn_in(window, async move |workspace, cx| {
 2537            let buffer = create.await?;
 2538            workspace.update_in(cx, |workspace, window, cx| {
 2539                let editor =
 2540                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2541                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2542                editor
 2543            })
 2544        })
 2545    }
 2546
 2547    fn new_file_vertical(
 2548        workspace: &mut Workspace,
 2549        _: &workspace::NewFileSplitVertical,
 2550        window: &mut Window,
 2551        cx: &mut Context<Workspace>,
 2552    ) {
 2553        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2554    }
 2555
 2556    fn new_file_horizontal(
 2557        workspace: &mut Workspace,
 2558        _: &workspace::NewFileSplitHorizontal,
 2559        window: &mut Window,
 2560        cx: &mut Context<Workspace>,
 2561    ) {
 2562        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2563    }
 2564
 2565    fn new_file_in_direction(
 2566        workspace: &mut Workspace,
 2567        direction: SplitDirection,
 2568        window: &mut Window,
 2569        cx: &mut Context<Workspace>,
 2570    ) {
 2571        let project = workspace.project().clone();
 2572        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2573
 2574        cx.spawn_in(window, async move |workspace, cx| {
 2575            let buffer = create.await?;
 2576            workspace.update_in(cx, move |workspace, window, cx| {
 2577                workspace.split_item(
 2578                    direction,
 2579                    Box::new(
 2580                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2581                    ),
 2582                    window,
 2583                    cx,
 2584                )
 2585            })?;
 2586            anyhow::Ok(())
 2587        })
 2588        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2589            match e.error_code() {
 2590                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2591                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2592                e.error_tag("required").unwrap_or("the latest version")
 2593            )),
 2594                _ => None,
 2595            }
 2596        });
 2597    }
 2598
 2599    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2600        self.leader_id
 2601    }
 2602
 2603    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2604        &self.buffer
 2605    }
 2606
 2607    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2608        self.workspace.as_ref()?.0.upgrade()
 2609    }
 2610
 2611    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2612        self.buffer().read(cx).title(cx)
 2613    }
 2614
 2615    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2616        let git_blame_gutter_max_author_length = self
 2617            .render_git_blame_gutter(cx)
 2618            .then(|| {
 2619                if let Some(blame) = self.blame.as_ref() {
 2620                    let max_author_length =
 2621                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2622                    Some(max_author_length)
 2623                } else {
 2624                    None
 2625                }
 2626            })
 2627            .flatten();
 2628
 2629        EditorSnapshot {
 2630            mode: self.mode.clone(),
 2631            show_gutter: self.show_gutter,
 2632            show_line_numbers: self.show_line_numbers,
 2633            show_git_diff_gutter: self.show_git_diff_gutter,
 2634            show_code_actions: self.show_code_actions,
 2635            show_runnables: self.show_runnables,
 2636            show_breakpoints: self.show_breakpoints,
 2637            git_blame_gutter_max_author_length,
 2638            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2639            scroll_anchor: self.scroll_manager.anchor(),
 2640            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2641            placeholder_text: self.placeholder_text.clone(),
 2642            is_focused: self.focus_handle.is_focused(window),
 2643            current_line_highlight: self
 2644                .current_line_highlight
 2645                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2646            gutter_hovered: self.gutter_hovered,
 2647        }
 2648    }
 2649
 2650    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2651        self.buffer.read(cx).language_at(point, cx)
 2652    }
 2653
 2654    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2655        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2656    }
 2657
 2658    pub fn active_excerpt(
 2659        &self,
 2660        cx: &App,
 2661    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2662        self.buffer
 2663            .read(cx)
 2664            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2665    }
 2666
 2667    pub fn mode(&self) -> &EditorMode {
 2668        &self.mode
 2669    }
 2670
 2671    pub fn set_mode(&mut self, mode: EditorMode) {
 2672        self.mode = mode;
 2673    }
 2674
 2675    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2676        self.collaboration_hub.as_deref()
 2677    }
 2678
 2679    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2680        self.collaboration_hub = Some(hub);
 2681    }
 2682
 2683    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2684        self.in_project_search = in_project_search;
 2685    }
 2686
 2687    pub fn set_custom_context_menu(
 2688        &mut self,
 2689        f: impl 'static
 2690        + Fn(
 2691            &mut Self,
 2692            DisplayPoint,
 2693            &mut Window,
 2694            &mut Context<Self>,
 2695        ) -> Option<Entity<ui::ContextMenu>>,
 2696    ) {
 2697        self.custom_context_menu = Some(Box::new(f))
 2698    }
 2699
 2700    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2701        self.completion_provider = provider;
 2702    }
 2703
 2704    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2705        self.semantics_provider.clone()
 2706    }
 2707
 2708    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2709        self.semantics_provider = provider;
 2710    }
 2711
 2712    pub fn set_edit_prediction_provider<T>(
 2713        &mut self,
 2714        provider: Option<Entity<T>>,
 2715        window: &mut Window,
 2716        cx: &mut Context<Self>,
 2717    ) where
 2718        T: EditPredictionProvider,
 2719    {
 2720        self.edit_prediction_provider =
 2721            provider.map(|provider| RegisteredInlineCompletionProvider {
 2722                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2723                    if this.focus_handle.is_focused(window) {
 2724                        this.update_visible_inline_completion(window, cx);
 2725                    }
 2726                }),
 2727                provider: Arc::new(provider),
 2728            });
 2729        self.update_edit_prediction_settings(cx);
 2730        self.refresh_inline_completion(false, false, window, cx);
 2731    }
 2732
 2733    pub fn placeholder_text(&self) -> Option<&str> {
 2734        self.placeholder_text.as_deref()
 2735    }
 2736
 2737    pub fn set_placeholder_text(
 2738        &mut self,
 2739        placeholder_text: impl Into<Arc<str>>,
 2740        cx: &mut Context<Self>,
 2741    ) {
 2742        let placeholder_text = Some(placeholder_text.into());
 2743        if self.placeholder_text != placeholder_text {
 2744            self.placeholder_text = placeholder_text;
 2745            cx.notify();
 2746        }
 2747    }
 2748
 2749    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2750        self.cursor_shape = cursor_shape;
 2751
 2752        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2753        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2754
 2755        cx.notify();
 2756    }
 2757
 2758    pub fn set_current_line_highlight(
 2759        &mut self,
 2760        current_line_highlight: Option<CurrentLineHighlight>,
 2761    ) {
 2762        self.current_line_highlight = current_line_highlight;
 2763    }
 2764
 2765    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2766        self.collapse_matches = collapse_matches;
 2767    }
 2768
 2769    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2770        let buffers = self.buffer.read(cx).all_buffers();
 2771        let Some(project) = self.project.as_ref() else {
 2772            return;
 2773        };
 2774        project.update(cx, |project, cx| {
 2775            for buffer in buffers {
 2776                self.registered_buffers
 2777                    .entry(buffer.read(cx).remote_id())
 2778                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2779            }
 2780        })
 2781    }
 2782
 2783    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2784        if self.collapse_matches {
 2785            return range.start..range.start;
 2786        }
 2787        range.clone()
 2788    }
 2789
 2790    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2791        if self.display_map.read(cx).clip_at_line_ends != clip {
 2792            self.display_map
 2793                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2794        }
 2795    }
 2796
 2797    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2798        self.input_enabled = input_enabled;
 2799    }
 2800
 2801    pub fn set_inline_completions_hidden_for_vim_mode(
 2802        &mut self,
 2803        hidden: bool,
 2804        window: &mut Window,
 2805        cx: &mut Context<Self>,
 2806    ) {
 2807        if hidden != self.inline_completions_hidden_for_vim_mode {
 2808            self.inline_completions_hidden_for_vim_mode = hidden;
 2809            if hidden {
 2810                self.update_visible_inline_completion(window, cx);
 2811            } else {
 2812                self.refresh_inline_completion(true, false, window, cx);
 2813            }
 2814        }
 2815    }
 2816
 2817    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2818        self.menu_inline_completions_policy = value;
 2819    }
 2820
 2821    pub fn set_autoindent(&mut self, autoindent: bool) {
 2822        if autoindent {
 2823            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2824        } else {
 2825            self.autoindent_mode = None;
 2826        }
 2827    }
 2828
 2829    pub fn read_only(&self, cx: &App) -> bool {
 2830        self.read_only || self.buffer.read(cx).read_only()
 2831    }
 2832
 2833    pub fn set_read_only(&mut self, read_only: bool) {
 2834        self.read_only = read_only;
 2835    }
 2836
 2837    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2838        self.use_autoclose = autoclose;
 2839    }
 2840
 2841    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2842        self.use_auto_surround = auto_surround;
 2843    }
 2844
 2845    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2846        self.auto_replace_emoji_shortcode = auto_replace;
 2847    }
 2848
 2849    pub fn toggle_edit_predictions(
 2850        &mut self,
 2851        _: &ToggleEditPrediction,
 2852        window: &mut Window,
 2853        cx: &mut Context<Self>,
 2854    ) {
 2855        if self.show_inline_completions_override.is_some() {
 2856            self.set_show_edit_predictions(None, window, cx);
 2857        } else {
 2858            let show_edit_predictions = !self.edit_predictions_enabled();
 2859            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2860        }
 2861    }
 2862
 2863    pub fn set_show_edit_predictions(
 2864        &mut self,
 2865        show_edit_predictions: Option<bool>,
 2866        window: &mut Window,
 2867        cx: &mut Context<Self>,
 2868    ) {
 2869        self.show_inline_completions_override = show_edit_predictions;
 2870        self.update_edit_prediction_settings(cx);
 2871
 2872        if let Some(false) = show_edit_predictions {
 2873            self.discard_inline_completion(false, cx);
 2874        } else {
 2875            self.refresh_inline_completion(false, true, window, cx);
 2876        }
 2877    }
 2878
 2879    fn inline_completions_disabled_in_scope(
 2880        &self,
 2881        buffer: &Entity<Buffer>,
 2882        buffer_position: language::Anchor,
 2883        cx: &App,
 2884    ) -> bool {
 2885        let snapshot = buffer.read(cx).snapshot();
 2886        let settings = snapshot.settings_at(buffer_position, cx);
 2887
 2888        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2889            return false;
 2890        };
 2891
 2892        scope.override_name().map_or(false, |scope_name| {
 2893            settings
 2894                .edit_predictions_disabled_in
 2895                .iter()
 2896                .any(|s| s == scope_name)
 2897        })
 2898    }
 2899
 2900    pub fn set_use_modal_editing(&mut self, to: bool) {
 2901        self.use_modal_editing = to;
 2902    }
 2903
 2904    pub fn use_modal_editing(&self) -> bool {
 2905        self.use_modal_editing
 2906    }
 2907
 2908    fn selections_did_change(
 2909        &mut self,
 2910        local: bool,
 2911        old_cursor_position: &Anchor,
 2912        effects: SelectionEffects,
 2913        window: &mut Window,
 2914        cx: &mut Context<Self>,
 2915    ) {
 2916        window.invalidate_character_coordinates();
 2917
 2918        // Copy selections to primary selection buffer
 2919        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2920        if local {
 2921            let selections = self.selections.all::<usize>(cx);
 2922            let buffer_handle = self.buffer.read(cx).read(cx);
 2923
 2924            let mut text = String::new();
 2925            for (index, selection) in selections.iter().enumerate() {
 2926                let text_for_selection = buffer_handle
 2927                    .text_for_range(selection.start..selection.end)
 2928                    .collect::<String>();
 2929
 2930                text.push_str(&text_for_selection);
 2931                if index != selections.len() - 1 {
 2932                    text.push('\n');
 2933                }
 2934            }
 2935
 2936            if !text.is_empty() {
 2937                cx.write_to_primary(ClipboardItem::new_string(text));
 2938            }
 2939        }
 2940
 2941        let selection_anchors = self.selections.disjoint_anchors();
 2942
 2943        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2944            self.buffer.update(cx, |buffer, cx| {
 2945                buffer.set_active_selections(
 2946                    &selection_anchors,
 2947                    self.selections.line_mode,
 2948                    self.cursor_shape,
 2949                    cx,
 2950                )
 2951            });
 2952        }
 2953        let display_map = self
 2954            .display_map
 2955            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2956        let buffer = &display_map.buffer_snapshot;
 2957        if self.selections.count() == 1 {
 2958            self.add_selections_state = None;
 2959        }
 2960        self.select_next_state = None;
 2961        self.select_prev_state = None;
 2962        self.select_syntax_node_history.try_clear();
 2963        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 2964        self.snippet_stack.invalidate(&selection_anchors, buffer);
 2965        self.take_rename(false, window, cx);
 2966
 2967        let newest_selection = self.selections.newest_anchor();
 2968        let new_cursor_position = newest_selection.head();
 2969        let selection_start = newest_selection.start;
 2970
 2971        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 2972            self.push_to_nav_history(
 2973                *old_cursor_position,
 2974                Some(new_cursor_position.to_point(buffer)),
 2975                false,
 2976                effects.nav_history == Some(true),
 2977                cx,
 2978            );
 2979        }
 2980
 2981        if local {
 2982            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2983                if !self.registered_buffers.contains_key(&buffer_id) {
 2984                    if let Some(project) = self.project.as_ref() {
 2985                        project.update(cx, |project, cx| {
 2986                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2987                                return;
 2988                            };
 2989                            self.registered_buffers.insert(
 2990                                buffer_id,
 2991                                project.register_buffer_with_language_servers(&buffer, cx),
 2992                            );
 2993                        })
 2994                    }
 2995                }
 2996            }
 2997
 2998            let mut context_menu = self.context_menu.borrow_mut();
 2999            let completion_menu = match context_menu.as_ref() {
 3000                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3001                Some(CodeContextMenu::CodeActions(_)) => {
 3002                    *context_menu = None;
 3003                    None
 3004                }
 3005                None => None,
 3006            };
 3007            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3008            drop(context_menu);
 3009
 3010            if effects.completions {
 3011                if let Some(completion_position) = completion_position {
 3012                    let start_offset = selection_start.to_offset(buffer);
 3013                    let position_matches = start_offset == completion_position.to_offset(buffer);
 3014                    let continue_showing = if position_matches {
 3015                        if self.snippet_stack.is_empty() {
 3016                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3017                        } else {
 3018                            // Snippet choices can be shown even when the cursor is in whitespace.
 3019                            // Dismissing the menu with actions like backspace is handled by
 3020                            // invalidation regions.
 3021                            true
 3022                        }
 3023                    } else {
 3024                        false
 3025                    };
 3026
 3027                    if continue_showing {
 3028                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3029                    } else {
 3030                        self.hide_context_menu(window, cx);
 3031                    }
 3032                }
 3033            }
 3034
 3035            hide_hover(self, cx);
 3036
 3037            if old_cursor_position.to_display_point(&display_map).row()
 3038                != new_cursor_position.to_display_point(&display_map).row()
 3039            {
 3040                self.available_code_actions.take();
 3041            }
 3042            self.refresh_code_actions(window, cx);
 3043            self.refresh_document_highlights(cx);
 3044            self.refresh_selected_text_highlights(false, window, cx);
 3045            refresh_matching_bracket_highlights(self, window, cx);
 3046            self.update_visible_inline_completion(window, cx);
 3047            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3048            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3049            self.inline_blame_popover.take();
 3050            if self.git_blame_inline_enabled {
 3051                self.start_inline_blame_timer(window, cx);
 3052            }
 3053        }
 3054
 3055        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3056        cx.emit(EditorEvent::SelectionsChanged { local });
 3057
 3058        let selections = &self.selections.disjoint;
 3059        if selections.len() == 1 {
 3060            cx.emit(SearchEvent::ActiveMatchChanged)
 3061        }
 3062        if local {
 3063            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3064                let inmemory_selections = selections
 3065                    .iter()
 3066                    .map(|s| {
 3067                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3068                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3069                    })
 3070                    .collect();
 3071                self.update_restoration_data(cx, |data| {
 3072                    data.selections = inmemory_selections;
 3073                });
 3074
 3075                if WorkspaceSettings::get(None, cx).restore_on_startup
 3076                    != RestoreOnStartupBehavior::None
 3077                {
 3078                    if let Some(workspace_id) =
 3079                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 3080                    {
 3081                        let snapshot = self.buffer().read(cx).snapshot(cx);
 3082                        let selections = selections.clone();
 3083                        let background_executor = cx.background_executor().clone();
 3084                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3085                        self.serialize_selections = cx.background_spawn(async move {
 3086                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3087                            let db_selections = selections
 3088                                .iter()
 3089                                .map(|selection| {
 3090                                    (
 3091                                        selection.start.to_offset(&snapshot),
 3092                                        selection.end.to_offset(&snapshot),
 3093                                    )
 3094                                })
 3095                                .collect();
 3096
 3097                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3098                                .await
 3099                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3100                                .log_err();
 3101                        });
 3102                    }
 3103                }
 3104            }
 3105        }
 3106
 3107        cx.notify();
 3108    }
 3109
 3110    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3111        use text::ToOffset as _;
 3112        use text::ToPoint as _;
 3113
 3114        if self.mode.is_minimap()
 3115            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3116        {
 3117            return;
 3118        }
 3119
 3120        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3121            return;
 3122        };
 3123
 3124        let snapshot = singleton.read(cx).snapshot();
 3125        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3126            let display_snapshot = display_map.snapshot(cx);
 3127
 3128            display_snapshot
 3129                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3130                .map(|fold| {
 3131                    fold.range.start.text_anchor.to_point(&snapshot)
 3132                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3133                })
 3134                .collect()
 3135        });
 3136        self.update_restoration_data(cx, |data| {
 3137            data.folds = inmemory_folds;
 3138        });
 3139
 3140        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3141            return;
 3142        };
 3143        let background_executor = cx.background_executor().clone();
 3144        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3145        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3146            display_map
 3147                .snapshot(cx)
 3148                .folds_in_range(0..snapshot.len())
 3149                .map(|fold| {
 3150                    (
 3151                        fold.range.start.text_anchor.to_offset(&snapshot),
 3152                        fold.range.end.text_anchor.to_offset(&snapshot),
 3153                    )
 3154                })
 3155                .collect()
 3156        });
 3157        self.serialize_folds = cx.background_spawn(async move {
 3158            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3159            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3160                .await
 3161                .with_context(|| {
 3162                    format!(
 3163                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3164                    )
 3165                })
 3166                .log_err();
 3167        });
 3168    }
 3169
 3170    pub fn sync_selections(
 3171        &mut self,
 3172        other: Entity<Editor>,
 3173        cx: &mut Context<Self>,
 3174    ) -> gpui::Subscription {
 3175        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3176        self.selections.change_with(cx, |selections| {
 3177            selections.select_anchors(other_selections);
 3178        });
 3179
 3180        let other_subscription =
 3181            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3182                EditorEvent::SelectionsChanged { local: true } => {
 3183                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3184                    if other_selections.is_empty() {
 3185                        return;
 3186                    }
 3187                    this.selections.change_with(cx, |selections| {
 3188                        selections.select_anchors(other_selections);
 3189                    });
 3190                }
 3191                _ => {}
 3192            });
 3193
 3194        let this_subscription =
 3195            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3196                EditorEvent::SelectionsChanged { local: true } => {
 3197                    let these_selections = this.selections.disjoint.to_vec();
 3198                    if these_selections.is_empty() {
 3199                        return;
 3200                    }
 3201                    other.update(cx, |other_editor, cx| {
 3202                        other_editor.selections.change_with(cx, |selections| {
 3203                            selections.select_anchors(these_selections);
 3204                        })
 3205                    });
 3206                }
 3207                _ => {}
 3208            });
 3209
 3210        Subscription::join(other_subscription, this_subscription)
 3211    }
 3212
 3213    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3214    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3215    /// effects of selection change occur at the end of the transaction.
 3216    pub fn change_selections<R>(
 3217        &mut self,
 3218        effects: SelectionEffects,
 3219        window: &mut Window,
 3220        cx: &mut Context<Self>,
 3221        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3222    ) -> R {
 3223        if let Some(state) = &mut self.deferred_selection_effects_state {
 3224            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3225            state.effects.completions = effects.completions;
 3226            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3227            let (changed, result) = self.selections.change_with(cx, change);
 3228            state.changed |= changed;
 3229            return result;
 3230        }
 3231        let mut state = DeferredSelectionEffectsState {
 3232            changed: false,
 3233            effects,
 3234            old_cursor_position: self.selections.newest_anchor().head(),
 3235            history_entry: SelectionHistoryEntry {
 3236                selections: self.selections.disjoint_anchors(),
 3237                select_next_state: self.select_next_state.clone(),
 3238                select_prev_state: self.select_prev_state.clone(),
 3239                add_selections_state: self.add_selections_state.clone(),
 3240            },
 3241        };
 3242        let (changed, result) = self.selections.change_with(cx, change);
 3243        state.changed = state.changed || changed;
 3244        if self.defer_selection_effects {
 3245            self.deferred_selection_effects_state = Some(state);
 3246        } else {
 3247            self.apply_selection_effects(state, window, cx);
 3248        }
 3249        result
 3250    }
 3251
 3252    /// Defers the effects of selection change, so that the effects of multiple calls to
 3253    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3254    /// to selection history and the state of popovers based on selection position aren't
 3255    /// erroneously updated.
 3256    pub fn with_selection_effects_deferred<R>(
 3257        &mut self,
 3258        window: &mut Window,
 3259        cx: &mut Context<Self>,
 3260        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3261    ) -> R {
 3262        let already_deferred = self.defer_selection_effects;
 3263        self.defer_selection_effects = true;
 3264        let result = update(self, window, cx);
 3265        if !already_deferred {
 3266            self.defer_selection_effects = false;
 3267            if let Some(state) = self.deferred_selection_effects_state.take() {
 3268                self.apply_selection_effects(state, window, cx);
 3269            }
 3270        }
 3271        result
 3272    }
 3273
 3274    fn apply_selection_effects(
 3275        &mut self,
 3276        state: DeferredSelectionEffectsState,
 3277        window: &mut Window,
 3278        cx: &mut Context<Self>,
 3279    ) {
 3280        if state.changed {
 3281            self.selection_history.push(state.history_entry);
 3282
 3283            if let Some(autoscroll) = state.effects.scroll {
 3284                self.request_autoscroll(autoscroll, cx);
 3285            }
 3286
 3287            let old_cursor_position = &state.old_cursor_position;
 3288
 3289            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3290
 3291            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3292                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3293            }
 3294        }
 3295    }
 3296
 3297    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3298    where
 3299        I: IntoIterator<Item = (Range<S>, T)>,
 3300        S: ToOffset,
 3301        T: Into<Arc<str>>,
 3302    {
 3303        if self.read_only(cx) {
 3304            return;
 3305        }
 3306
 3307        self.buffer
 3308            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3309    }
 3310
 3311    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3312    where
 3313        I: IntoIterator<Item = (Range<S>, T)>,
 3314        S: ToOffset,
 3315        T: Into<Arc<str>>,
 3316    {
 3317        if self.read_only(cx) {
 3318            return;
 3319        }
 3320
 3321        self.buffer.update(cx, |buffer, cx| {
 3322            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3323        });
 3324    }
 3325
 3326    pub fn edit_with_block_indent<I, S, T>(
 3327        &mut self,
 3328        edits: I,
 3329        original_indent_columns: Vec<Option<u32>>,
 3330        cx: &mut Context<Self>,
 3331    ) where
 3332        I: IntoIterator<Item = (Range<S>, T)>,
 3333        S: ToOffset,
 3334        T: Into<Arc<str>>,
 3335    {
 3336        if self.read_only(cx) {
 3337            return;
 3338        }
 3339
 3340        self.buffer.update(cx, |buffer, cx| {
 3341            buffer.edit(
 3342                edits,
 3343                Some(AutoindentMode::Block {
 3344                    original_indent_columns,
 3345                }),
 3346                cx,
 3347            )
 3348        });
 3349    }
 3350
 3351    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3352        self.hide_context_menu(window, cx);
 3353
 3354        match phase {
 3355            SelectPhase::Begin {
 3356                position,
 3357                add,
 3358                click_count,
 3359            } => self.begin_selection(position, add, click_count, window, cx),
 3360            SelectPhase::BeginColumnar {
 3361                position,
 3362                goal_column,
 3363                reset,
 3364                mode,
 3365            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3366            SelectPhase::Extend {
 3367                position,
 3368                click_count,
 3369            } => self.extend_selection(position, click_count, window, cx),
 3370            SelectPhase::Update {
 3371                position,
 3372                goal_column,
 3373                scroll_delta,
 3374            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3375            SelectPhase::End => self.end_selection(window, cx),
 3376        }
 3377    }
 3378
 3379    fn extend_selection(
 3380        &mut self,
 3381        position: DisplayPoint,
 3382        click_count: usize,
 3383        window: &mut Window,
 3384        cx: &mut Context<Self>,
 3385    ) {
 3386        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3387        let tail = self.selections.newest::<usize>(cx).tail();
 3388        self.begin_selection(position, false, click_count, window, cx);
 3389
 3390        let position = position.to_offset(&display_map, Bias::Left);
 3391        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3392
 3393        let mut pending_selection = self
 3394            .selections
 3395            .pending_anchor()
 3396            .expect("extend_selection not called with pending selection");
 3397        if position >= tail {
 3398            pending_selection.start = tail_anchor;
 3399        } else {
 3400            pending_selection.end = tail_anchor;
 3401            pending_selection.reversed = true;
 3402        }
 3403
 3404        let mut pending_mode = self.selections.pending_mode().unwrap();
 3405        match &mut pending_mode {
 3406            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3407            _ => {}
 3408        }
 3409
 3410        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3411            SelectionEffects::scroll(Autoscroll::fit())
 3412        } else {
 3413            SelectionEffects::no_scroll()
 3414        };
 3415
 3416        self.change_selections(effects, window, cx, |s| {
 3417            s.set_pending(pending_selection, pending_mode)
 3418        });
 3419    }
 3420
 3421    fn begin_selection(
 3422        &mut self,
 3423        position: DisplayPoint,
 3424        add: bool,
 3425        click_count: usize,
 3426        window: &mut Window,
 3427        cx: &mut Context<Self>,
 3428    ) {
 3429        if !self.focus_handle.is_focused(window) {
 3430            self.last_focused_descendant = None;
 3431            window.focus(&self.focus_handle);
 3432        }
 3433
 3434        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3435        let buffer = &display_map.buffer_snapshot;
 3436        let position = display_map.clip_point(position, Bias::Left);
 3437
 3438        let start;
 3439        let end;
 3440        let mode;
 3441        let mut auto_scroll;
 3442        match click_count {
 3443            1 => {
 3444                start = buffer.anchor_before(position.to_point(&display_map));
 3445                end = start;
 3446                mode = SelectMode::Character;
 3447                auto_scroll = true;
 3448            }
 3449            2 => {
 3450                let position = display_map
 3451                    .clip_point(position, Bias::Left)
 3452                    .to_offset(&display_map, Bias::Left);
 3453                let (range, _) = buffer.surrounding_word(position, false);
 3454                start = buffer.anchor_before(range.start);
 3455                end = buffer.anchor_before(range.end);
 3456                mode = SelectMode::Word(start..end);
 3457                auto_scroll = true;
 3458            }
 3459            3 => {
 3460                let position = display_map
 3461                    .clip_point(position, Bias::Left)
 3462                    .to_point(&display_map);
 3463                let line_start = display_map.prev_line_boundary(position).0;
 3464                let next_line_start = buffer.clip_point(
 3465                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3466                    Bias::Left,
 3467                );
 3468                start = buffer.anchor_before(line_start);
 3469                end = buffer.anchor_before(next_line_start);
 3470                mode = SelectMode::Line(start..end);
 3471                auto_scroll = true;
 3472            }
 3473            _ => {
 3474                start = buffer.anchor_before(0);
 3475                end = buffer.anchor_before(buffer.len());
 3476                mode = SelectMode::All;
 3477                auto_scroll = false;
 3478            }
 3479        }
 3480        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3481
 3482        let point_to_delete: Option<usize> = {
 3483            let selected_points: Vec<Selection<Point>> =
 3484                self.selections.disjoint_in_range(start..end, cx);
 3485
 3486            if !add || click_count > 1 {
 3487                None
 3488            } else if !selected_points.is_empty() {
 3489                Some(selected_points[0].id)
 3490            } else {
 3491                let clicked_point_already_selected =
 3492                    self.selections.disjoint.iter().find(|selection| {
 3493                        selection.start.to_point(buffer) == start.to_point(buffer)
 3494                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3495                    });
 3496
 3497                clicked_point_already_selected.map(|selection| selection.id)
 3498            }
 3499        };
 3500
 3501        let selections_count = self.selections.count();
 3502        let effects = if auto_scroll {
 3503            SelectionEffects::default()
 3504        } else {
 3505            SelectionEffects::no_scroll()
 3506        };
 3507
 3508        self.change_selections(effects, window, cx, |s| {
 3509            if let Some(point_to_delete) = point_to_delete {
 3510                s.delete(point_to_delete);
 3511
 3512                if selections_count == 1 {
 3513                    s.set_pending_anchor_range(start..end, mode);
 3514                }
 3515            } else {
 3516                if !add {
 3517                    s.clear_disjoint();
 3518                }
 3519
 3520                s.set_pending_anchor_range(start..end, mode);
 3521            }
 3522        });
 3523    }
 3524
 3525    fn begin_columnar_selection(
 3526        &mut self,
 3527        position: DisplayPoint,
 3528        goal_column: u32,
 3529        reset: bool,
 3530        mode: ColumnarMode,
 3531        window: &mut Window,
 3532        cx: &mut Context<Self>,
 3533    ) {
 3534        if !self.focus_handle.is_focused(window) {
 3535            self.last_focused_descendant = None;
 3536            window.focus(&self.focus_handle);
 3537        }
 3538
 3539        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3540
 3541        if reset {
 3542            let pointer_position = display_map
 3543                .buffer_snapshot
 3544                .anchor_before(position.to_point(&display_map));
 3545
 3546            self.change_selections(
 3547                SelectionEffects::scroll(Autoscroll::newest()),
 3548                window,
 3549                cx,
 3550                |s| {
 3551                    s.clear_disjoint();
 3552                    s.set_pending_anchor_range(
 3553                        pointer_position..pointer_position,
 3554                        SelectMode::Character,
 3555                    );
 3556                },
 3557            );
 3558        };
 3559
 3560        let tail = self.selections.newest::<Point>(cx).tail();
 3561        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3562        self.columnar_selection_state = match mode {
 3563            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3564                selection_tail: selection_anchor,
 3565                display_point: if reset {
 3566                    if position.column() != goal_column {
 3567                        Some(DisplayPoint::new(position.row(), goal_column))
 3568                    } else {
 3569                        None
 3570                    }
 3571                } else {
 3572                    None
 3573                },
 3574            }),
 3575            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3576                selection_tail: selection_anchor,
 3577            }),
 3578        };
 3579
 3580        if !reset {
 3581            self.select_columns(position, goal_column, &display_map, window, cx);
 3582        }
 3583    }
 3584
 3585    fn update_selection(
 3586        &mut self,
 3587        position: DisplayPoint,
 3588        goal_column: u32,
 3589        scroll_delta: gpui::Point<f32>,
 3590        window: &mut Window,
 3591        cx: &mut Context<Self>,
 3592    ) {
 3593        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3594
 3595        if self.columnar_selection_state.is_some() {
 3596            self.select_columns(position, goal_column, &display_map, window, cx);
 3597        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3598            let buffer = &display_map.buffer_snapshot;
 3599            let head;
 3600            let tail;
 3601            let mode = self.selections.pending_mode().unwrap();
 3602            match &mode {
 3603                SelectMode::Character => {
 3604                    head = position.to_point(&display_map);
 3605                    tail = pending.tail().to_point(buffer);
 3606                }
 3607                SelectMode::Word(original_range) => {
 3608                    let offset = display_map
 3609                        .clip_point(position, Bias::Left)
 3610                        .to_offset(&display_map, Bias::Left);
 3611                    let original_range = original_range.to_offset(buffer);
 3612
 3613                    let head_offset = if buffer.is_inside_word(offset, false)
 3614                        || original_range.contains(&offset)
 3615                    {
 3616                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3617                        if word_range.start < original_range.start {
 3618                            word_range.start
 3619                        } else {
 3620                            word_range.end
 3621                        }
 3622                    } else {
 3623                        offset
 3624                    };
 3625
 3626                    head = head_offset.to_point(buffer);
 3627                    if head_offset <= original_range.start {
 3628                        tail = original_range.end.to_point(buffer);
 3629                    } else {
 3630                        tail = original_range.start.to_point(buffer);
 3631                    }
 3632                }
 3633                SelectMode::Line(original_range) => {
 3634                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3635
 3636                    let position = display_map
 3637                        .clip_point(position, Bias::Left)
 3638                        .to_point(&display_map);
 3639                    let line_start = display_map.prev_line_boundary(position).0;
 3640                    let next_line_start = buffer.clip_point(
 3641                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3642                        Bias::Left,
 3643                    );
 3644
 3645                    if line_start < original_range.start {
 3646                        head = line_start
 3647                    } else {
 3648                        head = next_line_start
 3649                    }
 3650
 3651                    if head <= original_range.start {
 3652                        tail = original_range.end;
 3653                    } else {
 3654                        tail = original_range.start;
 3655                    }
 3656                }
 3657                SelectMode::All => {
 3658                    return;
 3659                }
 3660            };
 3661
 3662            if head < tail {
 3663                pending.start = buffer.anchor_before(head);
 3664                pending.end = buffer.anchor_before(tail);
 3665                pending.reversed = true;
 3666            } else {
 3667                pending.start = buffer.anchor_before(tail);
 3668                pending.end = buffer.anchor_before(head);
 3669                pending.reversed = false;
 3670            }
 3671
 3672            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3673                s.set_pending(pending, mode);
 3674            });
 3675        } else {
 3676            log::error!("update_selection dispatched with no pending selection");
 3677            return;
 3678        }
 3679
 3680        self.apply_scroll_delta(scroll_delta, window, cx);
 3681        cx.notify();
 3682    }
 3683
 3684    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3685        self.columnar_selection_state.take();
 3686        if self.selections.pending_anchor().is_some() {
 3687            let selections = self.selections.all::<usize>(cx);
 3688            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3689                s.select(selections);
 3690                s.clear_pending();
 3691            });
 3692        }
 3693    }
 3694
 3695    fn select_columns(
 3696        &mut self,
 3697        head: DisplayPoint,
 3698        goal_column: u32,
 3699        display_map: &DisplaySnapshot,
 3700        window: &mut Window,
 3701        cx: &mut Context<Self>,
 3702    ) {
 3703        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3704            return;
 3705        };
 3706
 3707        let tail = match columnar_state {
 3708            ColumnarSelectionState::FromMouse {
 3709                selection_tail,
 3710                display_point,
 3711            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(&display_map)),
 3712            ColumnarSelectionState::FromSelection { selection_tail } => {
 3713                selection_tail.to_display_point(&display_map)
 3714            }
 3715        };
 3716
 3717        let start_row = cmp::min(tail.row(), head.row());
 3718        let end_row = cmp::max(tail.row(), head.row());
 3719        let start_column = cmp::min(tail.column(), goal_column);
 3720        let end_column = cmp::max(tail.column(), goal_column);
 3721        let reversed = start_column < tail.column();
 3722
 3723        let selection_ranges = (start_row.0..=end_row.0)
 3724            .map(DisplayRow)
 3725            .filter_map(|row| {
 3726                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3727                    || start_column <= display_map.line_len(row))
 3728                    && !display_map.is_block_line(row)
 3729                {
 3730                    let start = display_map
 3731                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3732                        .to_point(display_map);
 3733                    let end = display_map
 3734                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3735                        .to_point(display_map);
 3736                    if reversed {
 3737                        Some(end..start)
 3738                    } else {
 3739                        Some(start..end)
 3740                    }
 3741                } else {
 3742                    None
 3743                }
 3744            })
 3745            .collect::<Vec<_>>();
 3746
 3747        let ranges = match columnar_state {
 3748            ColumnarSelectionState::FromMouse { .. } => {
 3749                let mut non_empty_ranges = selection_ranges
 3750                    .iter()
 3751                    .filter(|selection_range| selection_range.start != selection_range.end)
 3752                    .peekable();
 3753                if non_empty_ranges.peek().is_some() {
 3754                    non_empty_ranges.cloned().collect()
 3755                } else {
 3756                    selection_ranges
 3757                }
 3758            }
 3759            _ => selection_ranges,
 3760        };
 3761
 3762        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3763            s.select_ranges(ranges);
 3764        });
 3765        cx.notify();
 3766    }
 3767
 3768    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3769        self.selections
 3770            .all_adjusted(cx)
 3771            .iter()
 3772            .any(|selection| !selection.is_empty())
 3773    }
 3774
 3775    pub fn has_pending_nonempty_selection(&self) -> bool {
 3776        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3777            Some(Selection { start, end, .. }) => start != end,
 3778            None => false,
 3779        };
 3780
 3781        pending_nonempty_selection
 3782            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3783    }
 3784
 3785    pub fn has_pending_selection(&self) -> bool {
 3786        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3787    }
 3788
 3789    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3790        self.selection_mark_mode = false;
 3791        self.selection_drag_state = SelectionDragState::None;
 3792
 3793        if self.clear_expanded_diff_hunks(cx) {
 3794            cx.notify();
 3795            return;
 3796        }
 3797        if self.dismiss_menus_and_popups(true, window, cx) {
 3798            return;
 3799        }
 3800
 3801        if self.mode.is_full()
 3802            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3803        {
 3804            return;
 3805        }
 3806
 3807        cx.propagate();
 3808    }
 3809
 3810    pub fn dismiss_menus_and_popups(
 3811        &mut self,
 3812        is_user_requested: bool,
 3813        window: &mut Window,
 3814        cx: &mut Context<Self>,
 3815    ) -> bool {
 3816        if self.take_rename(false, window, cx).is_some() {
 3817            return true;
 3818        }
 3819
 3820        if hide_hover(self, cx) {
 3821            return true;
 3822        }
 3823
 3824        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3825            return true;
 3826        }
 3827
 3828        if self.hide_context_menu(window, cx).is_some() {
 3829            return true;
 3830        }
 3831
 3832        if self.mouse_context_menu.take().is_some() {
 3833            return true;
 3834        }
 3835
 3836        if is_user_requested && self.discard_inline_completion(true, cx) {
 3837            return true;
 3838        }
 3839
 3840        if self.snippet_stack.pop().is_some() {
 3841            return true;
 3842        }
 3843
 3844        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3845            self.dismiss_diagnostics(cx);
 3846            return true;
 3847        }
 3848
 3849        false
 3850    }
 3851
 3852    fn linked_editing_ranges_for(
 3853        &self,
 3854        selection: Range<text::Anchor>,
 3855        cx: &App,
 3856    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3857        if self.linked_edit_ranges.is_empty() {
 3858            return None;
 3859        }
 3860        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3861            selection.end.buffer_id.and_then(|end_buffer_id| {
 3862                if selection.start.buffer_id != Some(end_buffer_id) {
 3863                    return None;
 3864                }
 3865                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3866                let snapshot = buffer.read(cx).snapshot();
 3867                self.linked_edit_ranges
 3868                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3869                    .map(|ranges| (ranges, snapshot, buffer))
 3870            })?;
 3871        use text::ToOffset as TO;
 3872        // find offset from the start of current range to current cursor position
 3873        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3874
 3875        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3876        let start_difference = start_offset - start_byte_offset;
 3877        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3878        let end_difference = end_offset - start_byte_offset;
 3879        // Current range has associated linked ranges.
 3880        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3881        for range in linked_ranges.iter() {
 3882            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3883            let end_offset = start_offset + end_difference;
 3884            let start_offset = start_offset + start_difference;
 3885            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3886                continue;
 3887            }
 3888            if self.selections.disjoint_anchor_ranges().any(|s| {
 3889                if s.start.buffer_id != selection.start.buffer_id
 3890                    || s.end.buffer_id != selection.end.buffer_id
 3891                {
 3892                    return false;
 3893                }
 3894                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3895                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3896            }) {
 3897                continue;
 3898            }
 3899            let start = buffer_snapshot.anchor_after(start_offset);
 3900            let end = buffer_snapshot.anchor_after(end_offset);
 3901            linked_edits
 3902                .entry(buffer.clone())
 3903                .or_default()
 3904                .push(start..end);
 3905        }
 3906        Some(linked_edits)
 3907    }
 3908
 3909    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3910        let text: Arc<str> = text.into();
 3911
 3912        if self.read_only(cx) {
 3913            return;
 3914        }
 3915
 3916        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3917
 3918        let selections = self.selections.all_adjusted(cx);
 3919        let mut bracket_inserted = false;
 3920        let mut edits = Vec::new();
 3921        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3922        let mut new_selections = Vec::with_capacity(selections.len());
 3923        let mut new_autoclose_regions = Vec::new();
 3924        let snapshot = self.buffer.read(cx).read(cx);
 3925        let mut clear_linked_edit_ranges = false;
 3926
 3927        for (selection, autoclose_region) in
 3928            self.selections_with_autoclose_regions(selections, &snapshot)
 3929        {
 3930            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3931                // Determine if the inserted text matches the opening or closing
 3932                // bracket of any of this language's bracket pairs.
 3933                let mut bracket_pair = None;
 3934                let mut is_bracket_pair_start = false;
 3935                let mut is_bracket_pair_end = false;
 3936                if !text.is_empty() {
 3937                    let mut bracket_pair_matching_end = None;
 3938                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3939                    //  and they are removing the character that triggered IME popup.
 3940                    for (pair, enabled) in scope.brackets() {
 3941                        if !pair.close && !pair.surround {
 3942                            continue;
 3943                        }
 3944
 3945                        if enabled && pair.start.ends_with(text.as_ref()) {
 3946                            let prefix_len = pair.start.len() - text.len();
 3947                            let preceding_text_matches_prefix = prefix_len == 0
 3948                                || (selection.start.column >= (prefix_len as u32)
 3949                                    && snapshot.contains_str_at(
 3950                                        Point::new(
 3951                                            selection.start.row,
 3952                                            selection.start.column - (prefix_len as u32),
 3953                                        ),
 3954                                        &pair.start[..prefix_len],
 3955                                    ));
 3956                            if preceding_text_matches_prefix {
 3957                                bracket_pair = Some(pair.clone());
 3958                                is_bracket_pair_start = true;
 3959                                break;
 3960                            }
 3961                        }
 3962                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3963                        {
 3964                            // take first bracket pair matching end, but don't break in case a later bracket
 3965                            // pair matches start
 3966                            bracket_pair_matching_end = Some(pair.clone());
 3967                        }
 3968                    }
 3969                    if let Some(end) = bracket_pair_matching_end
 3970                        && bracket_pair.is_none()
 3971                    {
 3972                        bracket_pair = Some(end);
 3973                        is_bracket_pair_end = true;
 3974                    }
 3975                }
 3976
 3977                if let Some(bracket_pair) = bracket_pair {
 3978                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3979                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3980                    let auto_surround =
 3981                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3982                    if selection.is_empty() {
 3983                        if is_bracket_pair_start {
 3984                            // If the inserted text is a suffix of an opening bracket and the
 3985                            // selection is preceded by the rest of the opening bracket, then
 3986                            // insert the closing bracket.
 3987                            let following_text_allows_autoclose = snapshot
 3988                                .chars_at(selection.start)
 3989                                .next()
 3990                                .map_or(true, |c| scope.should_autoclose_before(c));
 3991
 3992                            let preceding_text_allows_autoclose = selection.start.column == 0
 3993                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3994                                    true,
 3995                                    |c| {
 3996                                        bracket_pair.start != bracket_pair.end
 3997                                            || !snapshot
 3998                                                .char_classifier_at(selection.start)
 3999                                                .is_word(c)
 4000                                    },
 4001                                );
 4002
 4003                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4004                                && bracket_pair.start.len() == 1
 4005                            {
 4006                                let target = bracket_pair.start.chars().next().unwrap();
 4007                                let current_line_count = snapshot
 4008                                    .reversed_chars_at(selection.start)
 4009                                    .take_while(|&c| c != '\n')
 4010                                    .filter(|&c| c == target)
 4011                                    .count();
 4012                                current_line_count % 2 == 1
 4013                            } else {
 4014                                false
 4015                            };
 4016
 4017                            if autoclose
 4018                                && bracket_pair.close
 4019                                && following_text_allows_autoclose
 4020                                && preceding_text_allows_autoclose
 4021                                && !is_closing_quote
 4022                            {
 4023                                let anchor = snapshot.anchor_before(selection.end);
 4024                                new_selections.push((selection.map(|_| anchor), text.len()));
 4025                                new_autoclose_regions.push((
 4026                                    anchor,
 4027                                    text.len(),
 4028                                    selection.id,
 4029                                    bracket_pair.clone(),
 4030                                ));
 4031                                edits.push((
 4032                                    selection.range(),
 4033                                    format!("{}{}", text, bracket_pair.end).into(),
 4034                                ));
 4035                                bracket_inserted = true;
 4036                                continue;
 4037                            }
 4038                        }
 4039
 4040                        if let Some(region) = autoclose_region {
 4041                            // If the selection is followed by an auto-inserted closing bracket,
 4042                            // then don't insert that closing bracket again; just move the selection
 4043                            // past the closing bracket.
 4044                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4045                                && text.as_ref() == region.pair.end.as_str()
 4046                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4047                            if should_skip {
 4048                                let anchor = snapshot.anchor_after(selection.end);
 4049                                new_selections
 4050                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4051                                continue;
 4052                            }
 4053                        }
 4054
 4055                        let always_treat_brackets_as_autoclosed = snapshot
 4056                            .language_settings_at(selection.start, cx)
 4057                            .always_treat_brackets_as_autoclosed;
 4058                        if always_treat_brackets_as_autoclosed
 4059                            && is_bracket_pair_end
 4060                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4061                        {
 4062                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4063                            // and the inserted text is a closing bracket and the selection is followed
 4064                            // by the closing bracket then move the selection past the closing bracket.
 4065                            let anchor = snapshot.anchor_after(selection.end);
 4066                            new_selections.push((selection.map(|_| anchor), text.len()));
 4067                            continue;
 4068                        }
 4069                    }
 4070                    // If an opening bracket is 1 character long and is typed while
 4071                    // text is selected, then surround that text with the bracket pair.
 4072                    else if auto_surround
 4073                        && bracket_pair.surround
 4074                        && is_bracket_pair_start
 4075                        && bracket_pair.start.chars().count() == 1
 4076                    {
 4077                        edits.push((selection.start..selection.start, text.clone()));
 4078                        edits.push((
 4079                            selection.end..selection.end,
 4080                            bracket_pair.end.as_str().into(),
 4081                        ));
 4082                        bracket_inserted = true;
 4083                        new_selections.push((
 4084                            Selection {
 4085                                id: selection.id,
 4086                                start: snapshot.anchor_after(selection.start),
 4087                                end: snapshot.anchor_before(selection.end),
 4088                                reversed: selection.reversed,
 4089                                goal: selection.goal,
 4090                            },
 4091                            0,
 4092                        ));
 4093                        continue;
 4094                    }
 4095                }
 4096            }
 4097
 4098            if self.auto_replace_emoji_shortcode
 4099                && selection.is_empty()
 4100                && text.as_ref().ends_with(':')
 4101            {
 4102                if let Some(possible_emoji_short_code) =
 4103                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4104                {
 4105                    if !possible_emoji_short_code.is_empty() {
 4106                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 4107                            let emoji_shortcode_start = Point::new(
 4108                                selection.start.row,
 4109                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4110                            );
 4111
 4112                            // Remove shortcode from buffer
 4113                            edits.push((
 4114                                emoji_shortcode_start..selection.start,
 4115                                "".to_string().into(),
 4116                            ));
 4117                            new_selections.push((
 4118                                Selection {
 4119                                    id: selection.id,
 4120                                    start: snapshot.anchor_after(emoji_shortcode_start),
 4121                                    end: snapshot.anchor_before(selection.start),
 4122                                    reversed: selection.reversed,
 4123                                    goal: selection.goal,
 4124                                },
 4125                                0,
 4126                            ));
 4127
 4128                            // Insert emoji
 4129                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 4130                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4131                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 4132
 4133                            continue;
 4134                        }
 4135                    }
 4136                }
 4137            }
 4138
 4139            // If not handling any auto-close operation, then just replace the selected
 4140            // text with the given input and move the selection to the end of the
 4141            // newly inserted text.
 4142            let anchor = snapshot.anchor_after(selection.end);
 4143            if !self.linked_edit_ranges.is_empty() {
 4144                let start_anchor = snapshot.anchor_before(selection.start);
 4145
 4146                let is_word_char = text.chars().next().map_or(true, |char| {
 4147                    let classifier = snapshot
 4148                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4149                        .ignore_punctuation(true);
 4150                    classifier.is_word(char)
 4151                });
 4152
 4153                if is_word_char {
 4154                    if let Some(ranges) = self
 4155                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4156                    {
 4157                        for (buffer, edits) in ranges {
 4158                            linked_edits
 4159                                .entry(buffer.clone())
 4160                                .or_default()
 4161                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4162                        }
 4163                    }
 4164                } else {
 4165                    clear_linked_edit_ranges = true;
 4166                }
 4167            }
 4168
 4169            new_selections.push((selection.map(|_| anchor), 0));
 4170            edits.push((selection.start..selection.end, text.clone()));
 4171        }
 4172
 4173        drop(snapshot);
 4174
 4175        self.transact(window, cx, |this, window, cx| {
 4176            if clear_linked_edit_ranges {
 4177                this.linked_edit_ranges.clear();
 4178            }
 4179            let initial_buffer_versions =
 4180                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4181
 4182            this.buffer.update(cx, |buffer, cx| {
 4183                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4184            });
 4185            for (buffer, edits) in linked_edits {
 4186                buffer.update(cx, |buffer, cx| {
 4187                    let snapshot = buffer.snapshot();
 4188                    let edits = edits
 4189                        .into_iter()
 4190                        .map(|(range, text)| {
 4191                            use text::ToPoint as TP;
 4192                            let end_point = TP::to_point(&range.end, &snapshot);
 4193                            let start_point = TP::to_point(&range.start, &snapshot);
 4194                            (start_point..end_point, text)
 4195                        })
 4196                        .sorted_by_key(|(range, _)| range.start);
 4197                    buffer.edit(edits, None, cx);
 4198                })
 4199            }
 4200            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4201            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4202            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4203            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4204                .zip(new_selection_deltas)
 4205                .map(|(selection, delta)| Selection {
 4206                    id: selection.id,
 4207                    start: selection.start + delta,
 4208                    end: selection.end + delta,
 4209                    reversed: selection.reversed,
 4210                    goal: SelectionGoal::None,
 4211                })
 4212                .collect::<Vec<_>>();
 4213
 4214            let mut i = 0;
 4215            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4216                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4217                let start = map.buffer_snapshot.anchor_before(position);
 4218                let end = map.buffer_snapshot.anchor_after(position);
 4219                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4220                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4221                        Ordering::Less => i += 1,
 4222                        Ordering::Greater => break,
 4223                        Ordering::Equal => {
 4224                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4225                                Ordering::Less => i += 1,
 4226                                Ordering::Equal => break,
 4227                                Ordering::Greater => break,
 4228                            }
 4229                        }
 4230                    }
 4231                }
 4232                this.autoclose_regions.insert(
 4233                    i,
 4234                    AutocloseRegion {
 4235                        selection_id,
 4236                        range: start..end,
 4237                        pair,
 4238                    },
 4239                );
 4240            }
 4241
 4242            let had_active_inline_completion = this.has_active_inline_completion();
 4243            this.change_selections(
 4244                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4245                window,
 4246                cx,
 4247                |s| s.select(new_selections),
 4248            );
 4249
 4250            if !bracket_inserted {
 4251                if let Some(on_type_format_task) =
 4252                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4253                {
 4254                    on_type_format_task.detach_and_log_err(cx);
 4255                }
 4256            }
 4257
 4258            let editor_settings = EditorSettings::get_global(cx);
 4259            if bracket_inserted
 4260                && (editor_settings.auto_signature_help
 4261                    || editor_settings.show_signature_help_after_edits)
 4262            {
 4263                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4264            }
 4265
 4266            let trigger_in_words =
 4267                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4268            if this.hard_wrap.is_some() {
 4269                let latest: Range<Point> = this.selections.newest(cx).range();
 4270                if latest.is_empty()
 4271                    && this
 4272                        .buffer()
 4273                        .read(cx)
 4274                        .snapshot(cx)
 4275                        .line_len(MultiBufferRow(latest.start.row))
 4276                        == latest.start.column
 4277                {
 4278                    this.rewrap_impl(
 4279                        RewrapOptions {
 4280                            override_language_settings: true,
 4281                            preserve_existing_whitespace: true,
 4282                        },
 4283                        cx,
 4284                    )
 4285                }
 4286            }
 4287            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4288            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4289            this.refresh_inline_completion(true, false, window, cx);
 4290            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4291        });
 4292    }
 4293
 4294    fn find_possible_emoji_shortcode_at_position(
 4295        snapshot: &MultiBufferSnapshot,
 4296        position: Point,
 4297    ) -> Option<String> {
 4298        let mut chars = Vec::new();
 4299        let mut found_colon = false;
 4300        for char in snapshot.reversed_chars_at(position).take(100) {
 4301            // Found a possible emoji shortcode in the middle of the buffer
 4302            if found_colon {
 4303                if char.is_whitespace() {
 4304                    chars.reverse();
 4305                    return Some(chars.iter().collect());
 4306                }
 4307                // If the previous character is not a whitespace, we are in the middle of a word
 4308                // and we only want to complete the shortcode if the word is made up of other emojis
 4309                let mut containing_word = String::new();
 4310                for ch in snapshot
 4311                    .reversed_chars_at(position)
 4312                    .skip(chars.len() + 1)
 4313                    .take(100)
 4314                {
 4315                    if ch.is_whitespace() {
 4316                        break;
 4317                    }
 4318                    containing_word.push(ch);
 4319                }
 4320                let containing_word = containing_word.chars().rev().collect::<String>();
 4321                if util::word_consists_of_emojis(containing_word.as_str()) {
 4322                    chars.reverse();
 4323                    return Some(chars.iter().collect());
 4324                }
 4325            }
 4326
 4327            if char.is_whitespace() || !char.is_ascii() {
 4328                return None;
 4329            }
 4330            if char == ':' {
 4331                found_colon = true;
 4332            } else {
 4333                chars.push(char);
 4334            }
 4335        }
 4336        // Found a possible emoji shortcode at the beginning of the buffer
 4337        chars.reverse();
 4338        Some(chars.iter().collect())
 4339    }
 4340
 4341    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4342        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4343        self.transact(window, cx, |this, window, cx| {
 4344            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4345                let selections = this.selections.all::<usize>(cx);
 4346                let multi_buffer = this.buffer.read(cx);
 4347                let buffer = multi_buffer.snapshot(cx);
 4348                selections
 4349                    .iter()
 4350                    .map(|selection| {
 4351                        let start_point = selection.start.to_point(&buffer);
 4352                        let mut existing_indent =
 4353                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4354                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4355                        let start = selection.start;
 4356                        let end = selection.end;
 4357                        let selection_is_empty = start == end;
 4358                        let language_scope = buffer.language_scope_at(start);
 4359                        let (
 4360                            comment_delimiter,
 4361                            doc_delimiter,
 4362                            insert_extra_newline,
 4363                            indent_on_newline,
 4364                            indent_on_extra_newline,
 4365                        ) = if let Some(language) = &language_scope {
 4366                            let mut insert_extra_newline =
 4367                                insert_extra_newline_brackets(&buffer, start..end, language)
 4368                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4369
 4370                            // Comment extension on newline is allowed only for cursor selections
 4371                            let comment_delimiter = maybe!({
 4372                                if !selection_is_empty {
 4373                                    return None;
 4374                                }
 4375
 4376                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4377                                    return None;
 4378                                }
 4379
 4380                                let delimiters = language.line_comment_prefixes();
 4381                                let max_len_of_delimiter =
 4382                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4383                                let (snapshot, range) =
 4384                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4385
 4386                                let num_of_whitespaces = snapshot
 4387                                    .chars_for_range(range.clone())
 4388                                    .take_while(|c| c.is_whitespace())
 4389                                    .count();
 4390                                let comment_candidate = snapshot
 4391                                    .chars_for_range(range.clone())
 4392                                    .skip(num_of_whitespaces)
 4393                                    .take(max_len_of_delimiter)
 4394                                    .collect::<String>();
 4395                                let (delimiter, trimmed_len) = delimiters
 4396                                    .iter()
 4397                                    .filter_map(|delimiter| {
 4398                                        let prefix = delimiter.trim_end();
 4399                                        if comment_candidate.starts_with(prefix) {
 4400                                            Some((delimiter, prefix.len()))
 4401                                        } else {
 4402                                            None
 4403                                        }
 4404                                    })
 4405                                    .max_by_key(|(_, len)| *len)?;
 4406
 4407                                if let Some(BlockCommentConfig {
 4408                                    start: block_start, ..
 4409                                }) = language.block_comment()
 4410                                {
 4411                                    let block_start_trimmed = block_start.trim_end();
 4412                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4413                                        let line_content = snapshot
 4414                                            .chars_for_range(range)
 4415                                            .skip(num_of_whitespaces)
 4416                                            .take(block_start_trimmed.len())
 4417                                            .collect::<String>();
 4418
 4419                                        if line_content.starts_with(block_start_trimmed) {
 4420                                            return None;
 4421                                        }
 4422                                    }
 4423                                }
 4424
 4425                                let cursor_is_placed_after_comment_marker =
 4426                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4427                                if cursor_is_placed_after_comment_marker {
 4428                                    Some(delimiter.clone())
 4429                                } else {
 4430                                    None
 4431                                }
 4432                            });
 4433
 4434                            let mut indent_on_newline = IndentSize::spaces(0);
 4435                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4436
 4437                            let doc_delimiter = maybe!({
 4438                                if !selection_is_empty {
 4439                                    return None;
 4440                                }
 4441
 4442                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4443                                    return None;
 4444                                }
 4445
 4446                                let BlockCommentConfig {
 4447                                    start: start_tag,
 4448                                    end: end_tag,
 4449                                    prefix: delimiter,
 4450                                    tab_size: len,
 4451                                } = language.documentation_comment()?;
 4452                                let is_within_block_comment = buffer
 4453                                    .language_scope_at(start_point)
 4454                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4455                                if !is_within_block_comment {
 4456                                    return None;
 4457                                }
 4458
 4459                                let (snapshot, range) =
 4460                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4461
 4462                                let num_of_whitespaces = snapshot
 4463                                    .chars_for_range(range.clone())
 4464                                    .take_while(|c| c.is_whitespace())
 4465                                    .count();
 4466
 4467                                // 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.
 4468                                let column = start_point.column;
 4469                                let cursor_is_after_start_tag = {
 4470                                    let start_tag_len = start_tag.len();
 4471                                    let start_tag_line = snapshot
 4472                                        .chars_for_range(range.clone())
 4473                                        .skip(num_of_whitespaces)
 4474                                        .take(start_tag_len)
 4475                                        .collect::<String>();
 4476                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4477                                        num_of_whitespaces + start_tag_len <= column as usize
 4478                                    } else {
 4479                                        false
 4480                                    }
 4481                                };
 4482
 4483                                let cursor_is_after_delimiter = {
 4484                                    let delimiter_trim = delimiter.trim_end();
 4485                                    let delimiter_line = snapshot
 4486                                        .chars_for_range(range.clone())
 4487                                        .skip(num_of_whitespaces)
 4488                                        .take(delimiter_trim.len())
 4489                                        .collect::<String>();
 4490                                    if delimiter_line.starts_with(delimiter_trim) {
 4491                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4492                                    } else {
 4493                                        false
 4494                                    }
 4495                                };
 4496
 4497                                let cursor_is_before_end_tag_if_exists = {
 4498                                    let mut char_position = 0u32;
 4499                                    let mut end_tag_offset = None;
 4500
 4501                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4502                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4503                                            let chars_before_match =
 4504                                                chunk[..byte_pos].chars().count() as u32;
 4505                                            end_tag_offset =
 4506                                                Some(char_position + chars_before_match);
 4507                                            break 'outer;
 4508                                        }
 4509                                        char_position += chunk.chars().count() as u32;
 4510                                    }
 4511
 4512                                    if let Some(end_tag_offset) = end_tag_offset {
 4513                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4514                                        if cursor_is_after_start_tag {
 4515                                            if cursor_is_before_end_tag {
 4516                                                insert_extra_newline = true;
 4517                                            }
 4518                                            let cursor_is_at_start_of_end_tag =
 4519                                                column == end_tag_offset;
 4520                                            if cursor_is_at_start_of_end_tag {
 4521                                                indent_on_extra_newline.len = *len;
 4522                                            }
 4523                                        }
 4524                                        cursor_is_before_end_tag
 4525                                    } else {
 4526                                        true
 4527                                    }
 4528                                };
 4529
 4530                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4531                                    && cursor_is_before_end_tag_if_exists
 4532                                {
 4533                                    if cursor_is_after_start_tag {
 4534                                        indent_on_newline.len = *len;
 4535                                    }
 4536                                    Some(delimiter.clone())
 4537                                } else {
 4538                                    None
 4539                                }
 4540                            });
 4541
 4542                            (
 4543                                comment_delimiter,
 4544                                doc_delimiter,
 4545                                insert_extra_newline,
 4546                                indent_on_newline,
 4547                                indent_on_extra_newline,
 4548                            )
 4549                        } else {
 4550                            (
 4551                                None,
 4552                                None,
 4553                                false,
 4554                                IndentSize::default(),
 4555                                IndentSize::default(),
 4556                            )
 4557                        };
 4558
 4559                        let prevent_auto_indent = doc_delimiter.is_some();
 4560                        let delimiter = comment_delimiter.or(doc_delimiter);
 4561
 4562                        let capacity_for_delimiter =
 4563                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4564                        let mut new_text = String::with_capacity(
 4565                            1 + capacity_for_delimiter
 4566                                + existing_indent.len as usize
 4567                                + indent_on_newline.len as usize
 4568                                + indent_on_extra_newline.len as usize,
 4569                        );
 4570                        new_text.push('\n');
 4571                        new_text.extend(existing_indent.chars());
 4572                        new_text.extend(indent_on_newline.chars());
 4573
 4574                        if let Some(delimiter) = &delimiter {
 4575                            new_text.push_str(delimiter);
 4576                        }
 4577
 4578                        if insert_extra_newline {
 4579                            new_text.push('\n');
 4580                            new_text.extend(existing_indent.chars());
 4581                            new_text.extend(indent_on_extra_newline.chars());
 4582                        }
 4583
 4584                        let anchor = buffer.anchor_after(end);
 4585                        let new_selection = selection.map(|_| anchor);
 4586                        (
 4587                            ((start..end, new_text), prevent_auto_indent),
 4588                            (insert_extra_newline, new_selection),
 4589                        )
 4590                    })
 4591                    .unzip()
 4592            };
 4593
 4594            let mut auto_indent_edits = Vec::new();
 4595            let mut edits = Vec::new();
 4596            for (edit, prevent_auto_indent) in edits_with_flags {
 4597                if prevent_auto_indent {
 4598                    edits.push(edit);
 4599                } else {
 4600                    auto_indent_edits.push(edit);
 4601                }
 4602            }
 4603            if !edits.is_empty() {
 4604                this.edit(edits, cx);
 4605            }
 4606            if !auto_indent_edits.is_empty() {
 4607                this.edit_with_autoindent(auto_indent_edits, cx);
 4608            }
 4609
 4610            let buffer = this.buffer.read(cx).snapshot(cx);
 4611            let new_selections = selection_info
 4612                .into_iter()
 4613                .map(|(extra_newline_inserted, new_selection)| {
 4614                    let mut cursor = new_selection.end.to_point(&buffer);
 4615                    if extra_newline_inserted {
 4616                        cursor.row -= 1;
 4617                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4618                    }
 4619                    new_selection.map(|_| cursor)
 4620                })
 4621                .collect();
 4622
 4623            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4624            this.refresh_inline_completion(true, false, window, cx);
 4625        });
 4626    }
 4627
 4628    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4629        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4630
 4631        let buffer = self.buffer.read(cx);
 4632        let snapshot = buffer.snapshot(cx);
 4633
 4634        let mut edits = Vec::new();
 4635        let mut rows = Vec::new();
 4636
 4637        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4638            let cursor = selection.head();
 4639            let row = cursor.row;
 4640
 4641            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4642
 4643            let newline = "\n".to_string();
 4644            edits.push((start_of_line..start_of_line, newline));
 4645
 4646            rows.push(row + rows_inserted as u32);
 4647        }
 4648
 4649        self.transact(window, cx, |editor, window, cx| {
 4650            editor.edit(edits, cx);
 4651
 4652            editor.change_selections(Default::default(), window, cx, |s| {
 4653                let mut index = 0;
 4654                s.move_cursors_with(|map, _, _| {
 4655                    let row = rows[index];
 4656                    index += 1;
 4657
 4658                    let point = Point::new(row, 0);
 4659                    let boundary = map.next_line_boundary(point).1;
 4660                    let clipped = map.clip_point(boundary, Bias::Left);
 4661
 4662                    (clipped, SelectionGoal::None)
 4663                });
 4664            });
 4665
 4666            let mut indent_edits = Vec::new();
 4667            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4668            for row in rows {
 4669                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4670                for (row, indent) in indents {
 4671                    if indent.len == 0 {
 4672                        continue;
 4673                    }
 4674
 4675                    let text = match indent.kind {
 4676                        IndentKind::Space => " ".repeat(indent.len as usize),
 4677                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4678                    };
 4679                    let point = Point::new(row.0, 0);
 4680                    indent_edits.push((point..point, text));
 4681                }
 4682            }
 4683            editor.edit(indent_edits, cx);
 4684        });
 4685    }
 4686
 4687    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4688        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4689
 4690        let buffer = self.buffer.read(cx);
 4691        let snapshot = buffer.snapshot(cx);
 4692
 4693        let mut edits = Vec::new();
 4694        let mut rows = Vec::new();
 4695        let mut rows_inserted = 0;
 4696
 4697        for selection in self.selections.all_adjusted(cx) {
 4698            let cursor = selection.head();
 4699            let row = cursor.row;
 4700
 4701            let point = Point::new(row + 1, 0);
 4702            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4703
 4704            let newline = "\n".to_string();
 4705            edits.push((start_of_line..start_of_line, newline));
 4706
 4707            rows_inserted += 1;
 4708            rows.push(row + rows_inserted);
 4709        }
 4710
 4711        self.transact(window, cx, |editor, window, cx| {
 4712            editor.edit(edits, cx);
 4713
 4714            editor.change_selections(Default::default(), window, cx, |s| {
 4715                let mut index = 0;
 4716                s.move_cursors_with(|map, _, _| {
 4717                    let row = rows[index];
 4718                    index += 1;
 4719
 4720                    let point = Point::new(row, 0);
 4721                    let boundary = map.next_line_boundary(point).1;
 4722                    let clipped = map.clip_point(boundary, Bias::Left);
 4723
 4724                    (clipped, SelectionGoal::None)
 4725                });
 4726            });
 4727
 4728            let mut indent_edits = Vec::new();
 4729            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4730            for row in rows {
 4731                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4732                for (row, indent) in indents {
 4733                    if indent.len == 0 {
 4734                        continue;
 4735                    }
 4736
 4737                    let text = match indent.kind {
 4738                        IndentKind::Space => " ".repeat(indent.len as usize),
 4739                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4740                    };
 4741                    let point = Point::new(row.0, 0);
 4742                    indent_edits.push((point..point, text));
 4743                }
 4744            }
 4745            editor.edit(indent_edits, cx);
 4746        });
 4747    }
 4748
 4749    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4750        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4751            original_indent_columns: Vec::new(),
 4752        });
 4753        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4754    }
 4755
 4756    fn insert_with_autoindent_mode(
 4757        &mut self,
 4758        text: &str,
 4759        autoindent_mode: Option<AutoindentMode>,
 4760        window: &mut Window,
 4761        cx: &mut Context<Self>,
 4762    ) {
 4763        if self.read_only(cx) {
 4764            return;
 4765        }
 4766
 4767        let text: Arc<str> = text.into();
 4768        self.transact(window, cx, |this, window, cx| {
 4769            let old_selections = this.selections.all_adjusted(cx);
 4770            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4771                let anchors = {
 4772                    let snapshot = buffer.read(cx);
 4773                    old_selections
 4774                        .iter()
 4775                        .map(|s| {
 4776                            let anchor = snapshot.anchor_after(s.head());
 4777                            s.map(|_| anchor)
 4778                        })
 4779                        .collect::<Vec<_>>()
 4780                };
 4781                buffer.edit(
 4782                    old_selections
 4783                        .iter()
 4784                        .map(|s| (s.start..s.end, text.clone())),
 4785                    autoindent_mode,
 4786                    cx,
 4787                );
 4788                anchors
 4789            });
 4790
 4791            this.change_selections(Default::default(), window, cx, |s| {
 4792                s.select_anchors(selection_anchors);
 4793            });
 4794
 4795            cx.notify();
 4796        });
 4797    }
 4798
 4799    fn trigger_completion_on_input(
 4800        &mut self,
 4801        text: &str,
 4802        trigger_in_words: bool,
 4803        window: &mut Window,
 4804        cx: &mut Context<Self>,
 4805    ) {
 4806        let completions_source = self
 4807            .context_menu
 4808            .borrow()
 4809            .as_ref()
 4810            .and_then(|menu| match menu {
 4811                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4812                CodeContextMenu::CodeActions(_) => None,
 4813            });
 4814
 4815        match completions_source {
 4816            Some(CompletionsMenuSource::Words) => {
 4817                self.show_word_completions(&ShowWordCompletions, window, cx)
 4818            }
 4819            Some(CompletionsMenuSource::Normal)
 4820            | Some(CompletionsMenuSource::SnippetChoices)
 4821            | None
 4822                if self.is_completion_trigger(
 4823                    text,
 4824                    trigger_in_words,
 4825                    completions_source.is_some(),
 4826                    cx,
 4827                ) =>
 4828            {
 4829                self.show_completions(
 4830                    &ShowCompletions {
 4831                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4832                    },
 4833                    window,
 4834                    cx,
 4835                )
 4836            }
 4837            _ => {
 4838                self.hide_context_menu(window, cx);
 4839            }
 4840        }
 4841    }
 4842
 4843    fn is_completion_trigger(
 4844        &self,
 4845        text: &str,
 4846        trigger_in_words: bool,
 4847        menu_is_open: bool,
 4848        cx: &mut Context<Self>,
 4849    ) -> bool {
 4850        let position = self.selections.newest_anchor().head();
 4851        let multibuffer = self.buffer.read(cx);
 4852        let Some(buffer) = position
 4853            .buffer_id
 4854            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4855        else {
 4856            return false;
 4857        };
 4858
 4859        if let Some(completion_provider) = &self.completion_provider {
 4860            completion_provider.is_completion_trigger(
 4861                &buffer,
 4862                position.text_anchor,
 4863                text,
 4864                trigger_in_words,
 4865                menu_is_open,
 4866                cx,
 4867            )
 4868        } else {
 4869            false
 4870        }
 4871    }
 4872
 4873    /// If any empty selections is touching the start of its innermost containing autoclose
 4874    /// region, expand it to select the brackets.
 4875    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4876        let selections = self.selections.all::<usize>(cx);
 4877        let buffer = self.buffer.read(cx).read(cx);
 4878        let new_selections = self
 4879            .selections_with_autoclose_regions(selections, &buffer)
 4880            .map(|(mut selection, region)| {
 4881                if !selection.is_empty() {
 4882                    return selection;
 4883                }
 4884
 4885                if let Some(region) = region {
 4886                    let mut range = region.range.to_offset(&buffer);
 4887                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4888                        range.start -= region.pair.start.len();
 4889                        if buffer.contains_str_at(range.start, &region.pair.start)
 4890                            && buffer.contains_str_at(range.end, &region.pair.end)
 4891                        {
 4892                            range.end += region.pair.end.len();
 4893                            selection.start = range.start;
 4894                            selection.end = range.end;
 4895
 4896                            return selection;
 4897                        }
 4898                    }
 4899                }
 4900
 4901                let always_treat_brackets_as_autoclosed = buffer
 4902                    .language_settings_at(selection.start, cx)
 4903                    .always_treat_brackets_as_autoclosed;
 4904
 4905                if !always_treat_brackets_as_autoclosed {
 4906                    return selection;
 4907                }
 4908
 4909                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4910                    for (pair, enabled) in scope.brackets() {
 4911                        if !enabled || !pair.close {
 4912                            continue;
 4913                        }
 4914
 4915                        if buffer.contains_str_at(selection.start, &pair.end) {
 4916                            let pair_start_len = pair.start.len();
 4917                            if buffer.contains_str_at(
 4918                                selection.start.saturating_sub(pair_start_len),
 4919                                &pair.start,
 4920                            ) {
 4921                                selection.start -= pair_start_len;
 4922                                selection.end += pair.end.len();
 4923
 4924                                return selection;
 4925                            }
 4926                        }
 4927                    }
 4928                }
 4929
 4930                selection
 4931            })
 4932            .collect();
 4933
 4934        drop(buffer);
 4935        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 4936            selections.select(new_selections)
 4937        });
 4938    }
 4939
 4940    /// Iterate the given selections, and for each one, find the smallest surrounding
 4941    /// autoclose region. This uses the ordering of the selections and the autoclose
 4942    /// regions to avoid repeated comparisons.
 4943    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4944        &'a self,
 4945        selections: impl IntoIterator<Item = Selection<D>>,
 4946        buffer: &'a MultiBufferSnapshot,
 4947    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4948        let mut i = 0;
 4949        let mut regions = self.autoclose_regions.as_slice();
 4950        selections.into_iter().map(move |selection| {
 4951            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4952
 4953            let mut enclosing = None;
 4954            while let Some(pair_state) = regions.get(i) {
 4955                if pair_state.range.end.to_offset(buffer) < range.start {
 4956                    regions = &regions[i + 1..];
 4957                    i = 0;
 4958                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4959                    break;
 4960                } else {
 4961                    if pair_state.selection_id == selection.id {
 4962                        enclosing = Some(pair_state);
 4963                    }
 4964                    i += 1;
 4965                }
 4966            }
 4967
 4968            (selection, enclosing)
 4969        })
 4970    }
 4971
 4972    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 4973    fn invalidate_autoclose_regions(
 4974        &mut self,
 4975        mut selections: &[Selection<Anchor>],
 4976        buffer: &MultiBufferSnapshot,
 4977    ) {
 4978        self.autoclose_regions.retain(|state| {
 4979            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 4980                return false;
 4981            }
 4982
 4983            let mut i = 0;
 4984            while let Some(selection) = selections.get(i) {
 4985                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4986                    selections = &selections[1..];
 4987                    continue;
 4988                }
 4989                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4990                    break;
 4991                }
 4992                if selection.id == state.selection_id {
 4993                    return true;
 4994                } else {
 4995                    i += 1;
 4996                }
 4997            }
 4998            false
 4999        });
 5000    }
 5001
 5002    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5003        let offset = position.to_offset(buffer);
 5004        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5005        if offset > word_range.start && kind == Some(CharKind::Word) {
 5006            Some(
 5007                buffer
 5008                    .text_for_range(word_range.start..offset)
 5009                    .collect::<String>(),
 5010            )
 5011        } else {
 5012            None
 5013        }
 5014    }
 5015
 5016    pub fn toggle_inline_values(
 5017        &mut self,
 5018        _: &ToggleInlineValues,
 5019        _: &mut Window,
 5020        cx: &mut Context<Self>,
 5021    ) {
 5022        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5023
 5024        self.refresh_inline_values(cx);
 5025    }
 5026
 5027    pub fn toggle_inlay_hints(
 5028        &mut self,
 5029        _: &ToggleInlayHints,
 5030        _: &mut Window,
 5031        cx: &mut Context<Self>,
 5032    ) {
 5033        self.refresh_inlay_hints(
 5034            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5035            cx,
 5036        );
 5037    }
 5038
 5039    pub fn inlay_hints_enabled(&self) -> bool {
 5040        self.inlay_hint_cache.enabled
 5041    }
 5042
 5043    pub fn inline_values_enabled(&self) -> bool {
 5044        self.inline_value_cache.enabled
 5045    }
 5046
 5047    #[cfg(any(test, feature = "test-support"))]
 5048    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5049        self.display_map
 5050            .read(cx)
 5051            .current_inlays()
 5052            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5053            .cloned()
 5054            .collect()
 5055    }
 5056
 5057    #[cfg(any(test, feature = "test-support"))]
 5058    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5059        self.display_map
 5060            .read(cx)
 5061            .current_inlays()
 5062            .cloned()
 5063            .collect()
 5064    }
 5065
 5066    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5067        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5068            return;
 5069        }
 5070
 5071        let reason_description = reason.description();
 5072        let ignore_debounce = matches!(
 5073            reason,
 5074            InlayHintRefreshReason::SettingsChange(_)
 5075                | InlayHintRefreshReason::Toggle(_)
 5076                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5077                | InlayHintRefreshReason::ModifiersChanged(_)
 5078        );
 5079        let (invalidate_cache, required_languages) = match reason {
 5080            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5081                match self.inlay_hint_cache.modifiers_override(enabled) {
 5082                    Some(enabled) => {
 5083                        if enabled {
 5084                            (InvalidationStrategy::RefreshRequested, None)
 5085                        } else {
 5086                            self.splice_inlays(
 5087                                &self
 5088                                    .visible_inlay_hints(cx)
 5089                                    .iter()
 5090                                    .map(|inlay| inlay.id)
 5091                                    .collect::<Vec<InlayId>>(),
 5092                                Vec::new(),
 5093                                cx,
 5094                            );
 5095                            return;
 5096                        }
 5097                    }
 5098                    None => return,
 5099                }
 5100            }
 5101            InlayHintRefreshReason::Toggle(enabled) => {
 5102                if self.inlay_hint_cache.toggle(enabled) {
 5103                    if enabled {
 5104                        (InvalidationStrategy::RefreshRequested, None)
 5105                    } else {
 5106                        self.splice_inlays(
 5107                            &self
 5108                                .visible_inlay_hints(cx)
 5109                                .iter()
 5110                                .map(|inlay| inlay.id)
 5111                                .collect::<Vec<InlayId>>(),
 5112                            Vec::new(),
 5113                            cx,
 5114                        );
 5115                        return;
 5116                    }
 5117                } else {
 5118                    return;
 5119                }
 5120            }
 5121            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5122                match self.inlay_hint_cache.update_settings(
 5123                    &self.buffer,
 5124                    new_settings,
 5125                    self.visible_inlay_hints(cx),
 5126                    cx,
 5127                ) {
 5128                    ControlFlow::Break(Some(InlaySplice {
 5129                        to_remove,
 5130                        to_insert,
 5131                    })) => {
 5132                        self.splice_inlays(&to_remove, to_insert, cx);
 5133                        return;
 5134                    }
 5135                    ControlFlow::Break(None) => return,
 5136                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5137                }
 5138            }
 5139            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5140                if let Some(InlaySplice {
 5141                    to_remove,
 5142                    to_insert,
 5143                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5144                {
 5145                    self.splice_inlays(&to_remove, to_insert, cx);
 5146                }
 5147                self.display_map.update(cx, |display_map, _| {
 5148                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5149                });
 5150                return;
 5151            }
 5152            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5153            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5154                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5155            }
 5156            InlayHintRefreshReason::RefreshRequested => {
 5157                (InvalidationStrategy::RefreshRequested, None)
 5158            }
 5159        };
 5160
 5161        if let Some(InlaySplice {
 5162            to_remove,
 5163            to_insert,
 5164        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5165            reason_description,
 5166            self.visible_excerpts(required_languages.as_ref(), cx),
 5167            invalidate_cache,
 5168            ignore_debounce,
 5169            cx,
 5170        ) {
 5171            self.splice_inlays(&to_remove, to_insert, cx);
 5172        }
 5173    }
 5174
 5175    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5176        self.display_map
 5177            .read(cx)
 5178            .current_inlays()
 5179            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5180            .cloned()
 5181            .collect()
 5182    }
 5183
 5184    pub fn visible_excerpts(
 5185        &self,
 5186        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5187        cx: &mut Context<Editor>,
 5188    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5189        let Some(project) = self.project.as_ref() else {
 5190            return HashMap::default();
 5191        };
 5192        let project = project.read(cx);
 5193        let multi_buffer = self.buffer().read(cx);
 5194        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5195        let multi_buffer_visible_start = self
 5196            .scroll_manager
 5197            .anchor()
 5198            .anchor
 5199            .to_point(&multi_buffer_snapshot);
 5200        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5201            multi_buffer_visible_start
 5202                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5203            Bias::Left,
 5204        );
 5205        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5206        multi_buffer_snapshot
 5207            .range_to_buffer_ranges(multi_buffer_visible_range)
 5208            .into_iter()
 5209            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5210            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5211                let buffer_file = project::File::from_dyn(buffer.file())?;
 5212                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5213                let worktree_entry = buffer_worktree
 5214                    .read(cx)
 5215                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5216                if worktree_entry.is_ignored {
 5217                    return None;
 5218                }
 5219
 5220                let language = buffer.language()?;
 5221                if let Some(restrict_to_languages) = restrict_to_languages {
 5222                    if !restrict_to_languages.contains(language) {
 5223                        return None;
 5224                    }
 5225                }
 5226                Some((
 5227                    excerpt_id,
 5228                    (
 5229                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5230                        buffer.version().clone(),
 5231                        excerpt_visible_range,
 5232                    ),
 5233                ))
 5234            })
 5235            .collect()
 5236    }
 5237
 5238    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5239        TextLayoutDetails {
 5240            text_system: window.text_system().clone(),
 5241            editor_style: self.style.clone().unwrap(),
 5242            rem_size: window.rem_size(),
 5243            scroll_anchor: self.scroll_manager.anchor(),
 5244            visible_rows: self.visible_line_count(),
 5245            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5246        }
 5247    }
 5248
 5249    pub fn splice_inlays(
 5250        &self,
 5251        to_remove: &[InlayId],
 5252        to_insert: Vec<Inlay>,
 5253        cx: &mut Context<Self>,
 5254    ) {
 5255        self.display_map.update(cx, |display_map, cx| {
 5256            display_map.splice_inlays(to_remove, to_insert, cx)
 5257        });
 5258        cx.notify();
 5259    }
 5260
 5261    fn trigger_on_type_formatting(
 5262        &self,
 5263        input: String,
 5264        window: &mut Window,
 5265        cx: &mut Context<Self>,
 5266    ) -> Option<Task<Result<()>>> {
 5267        if input.len() != 1 {
 5268            return None;
 5269        }
 5270
 5271        let project = self.project.as_ref()?;
 5272        let position = self.selections.newest_anchor().head();
 5273        let (buffer, buffer_position) = self
 5274            .buffer
 5275            .read(cx)
 5276            .text_anchor_for_position(position, cx)?;
 5277
 5278        let settings = language_settings::language_settings(
 5279            buffer
 5280                .read(cx)
 5281                .language_at(buffer_position)
 5282                .map(|l| l.name()),
 5283            buffer.read(cx).file(),
 5284            cx,
 5285        );
 5286        if !settings.use_on_type_format {
 5287            return None;
 5288        }
 5289
 5290        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5291        // hence we do LSP request & edit on host side only — add formats to host's history.
 5292        let push_to_lsp_host_history = true;
 5293        // If this is not the host, append its history with new edits.
 5294        let push_to_client_history = project.read(cx).is_via_collab();
 5295
 5296        let on_type_formatting = project.update(cx, |project, cx| {
 5297            project.on_type_format(
 5298                buffer.clone(),
 5299                buffer_position,
 5300                input,
 5301                push_to_lsp_host_history,
 5302                cx,
 5303            )
 5304        });
 5305        Some(cx.spawn_in(window, async move |editor, cx| {
 5306            if let Some(transaction) = on_type_formatting.await? {
 5307                if push_to_client_history {
 5308                    buffer
 5309                        .update(cx, |buffer, _| {
 5310                            buffer.push_transaction(transaction, Instant::now());
 5311                            buffer.finalize_last_transaction();
 5312                        })
 5313                        .ok();
 5314                }
 5315                editor.update(cx, |editor, cx| {
 5316                    editor.refresh_document_highlights(cx);
 5317                })?;
 5318            }
 5319            Ok(())
 5320        }))
 5321    }
 5322
 5323    pub fn show_word_completions(
 5324        &mut self,
 5325        _: &ShowWordCompletions,
 5326        window: &mut Window,
 5327        cx: &mut Context<Self>,
 5328    ) {
 5329        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5330    }
 5331
 5332    pub fn show_completions(
 5333        &mut self,
 5334        options: &ShowCompletions,
 5335        window: &mut Window,
 5336        cx: &mut Context<Self>,
 5337    ) {
 5338        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5339    }
 5340
 5341    fn open_or_update_completions_menu(
 5342        &mut self,
 5343        requested_source: Option<CompletionsMenuSource>,
 5344        trigger: Option<&str>,
 5345        window: &mut Window,
 5346        cx: &mut Context<Self>,
 5347    ) {
 5348        if self.pending_rename.is_some() {
 5349            return;
 5350        }
 5351
 5352        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5353
 5354        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5355        // inserted and selected. To handle that case, the start of the selection is used so that
 5356        // the menu starts with all choices.
 5357        let position = self
 5358            .selections
 5359            .newest_anchor()
 5360            .start
 5361            .bias_right(&multibuffer_snapshot);
 5362        if position.diff_base_anchor.is_some() {
 5363            return;
 5364        }
 5365        let (buffer, buffer_position) =
 5366            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5367                output
 5368            } else {
 5369                return;
 5370            };
 5371        let buffer_snapshot = buffer.read(cx).snapshot();
 5372
 5373        let query: Option<Arc<String>> =
 5374            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5375
 5376        drop(multibuffer_snapshot);
 5377
 5378        let provider = match requested_source {
 5379            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5380            Some(CompletionsMenuSource::Words) => None,
 5381            Some(CompletionsMenuSource::SnippetChoices) => {
 5382                log::error!("bug: SnippetChoices requested_source is not handled");
 5383                None
 5384            }
 5385        };
 5386
 5387        let sort_completions = provider
 5388            .as_ref()
 5389            .map_or(false, |provider| provider.sort_completions());
 5390
 5391        let filter_completions = provider
 5392            .as_ref()
 5393            .map_or(true, |provider| provider.filter_completions());
 5394
 5395        let trigger_kind = match trigger {
 5396            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5397                CompletionTriggerKind::TRIGGER_CHARACTER
 5398            }
 5399            _ => CompletionTriggerKind::INVOKED,
 5400        };
 5401        let completion_context = CompletionContext {
 5402            trigger_character: trigger.and_then(|trigger| {
 5403                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5404                    Some(String::from(trigger))
 5405                } else {
 5406                    None
 5407                }
 5408            }),
 5409            trigger_kind,
 5410        };
 5411
 5412        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5413        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5414        // involve trigger chars, so this is skipped in that case.
 5415        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5416        {
 5417            let menu_is_open = matches!(
 5418                self.context_menu.borrow().as_ref(),
 5419                Some(CodeContextMenu::Completions(_))
 5420            );
 5421            if menu_is_open {
 5422                self.hide_context_menu(window, cx);
 5423            }
 5424        }
 5425
 5426        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5427            if filter_completions {
 5428                menu.filter(query.clone(), provider.clone(), window, cx);
 5429            }
 5430            // When `is_incomplete` is false, no need to re-query completions when the current query
 5431            // is a suffix of the initial query.
 5432            if !menu.is_incomplete {
 5433                // If the new query is a suffix of the old query (typing more characters) and
 5434                // the previous result was complete, the existing completions can be filtered.
 5435                //
 5436                // Note that this is always true for snippet completions.
 5437                let query_matches = match (&menu.initial_query, &query) {
 5438                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5439                    (None, _) => true,
 5440                    _ => false,
 5441                };
 5442                if query_matches {
 5443                    let position_matches = if menu.initial_position == position {
 5444                        true
 5445                    } else {
 5446                        let snapshot = self.buffer.read(cx).read(cx);
 5447                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5448                    };
 5449                    if position_matches {
 5450                        return;
 5451                    }
 5452                }
 5453            }
 5454        };
 5455
 5456        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5457            buffer_snapshot.surrounding_word(buffer_position, false)
 5458        {
 5459            let word_to_exclude = buffer_snapshot
 5460                .text_for_range(word_range.clone())
 5461                .collect::<String>();
 5462            (
 5463                buffer_snapshot.anchor_before(word_range.start)
 5464                    ..buffer_snapshot.anchor_after(buffer_position),
 5465                Some(word_to_exclude),
 5466            )
 5467        } else {
 5468            (buffer_position..buffer_position, None)
 5469        };
 5470
 5471        let language = buffer_snapshot
 5472            .language_at(buffer_position)
 5473            .map(|language| language.name());
 5474
 5475        let completion_settings =
 5476            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5477
 5478        let show_completion_documentation = buffer_snapshot
 5479            .settings_at(buffer_position, cx)
 5480            .show_completion_documentation;
 5481
 5482        // The document can be large, so stay in reasonable bounds when searching for words,
 5483        // otherwise completion pop-up might be slow to appear.
 5484        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5485        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5486        let min_word_search = buffer_snapshot.clip_point(
 5487            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5488            Bias::Left,
 5489        );
 5490        let max_word_search = buffer_snapshot.clip_point(
 5491            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5492            Bias::Right,
 5493        );
 5494        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5495            ..buffer_snapshot.point_to_offset(max_word_search);
 5496
 5497        let skip_digits = query
 5498            .as_ref()
 5499            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5500
 5501        let (mut words, provider_responses) = match &provider {
 5502            Some(provider) => {
 5503                let provider_responses = provider.completions(
 5504                    position.excerpt_id,
 5505                    &buffer,
 5506                    buffer_position,
 5507                    completion_context,
 5508                    window,
 5509                    cx,
 5510                );
 5511
 5512                let words = match completion_settings.words {
 5513                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5514                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5515                        .background_spawn(async move {
 5516                            buffer_snapshot.words_in_range(WordsQuery {
 5517                                fuzzy_contents: None,
 5518                                range: word_search_range,
 5519                                skip_digits,
 5520                            })
 5521                        }),
 5522                };
 5523
 5524                (words, provider_responses)
 5525            }
 5526            None => (
 5527                cx.background_spawn(async move {
 5528                    buffer_snapshot.words_in_range(WordsQuery {
 5529                        fuzzy_contents: None,
 5530                        range: word_search_range,
 5531                        skip_digits,
 5532                    })
 5533                }),
 5534                Task::ready(Ok(Vec::new())),
 5535            ),
 5536        };
 5537
 5538        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5539
 5540        let id = post_inc(&mut self.next_completion_id);
 5541        let task = cx.spawn_in(window, async move |editor, cx| {
 5542            let Ok(()) = editor.update(cx, |this, _| {
 5543                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5544            }) else {
 5545                return;
 5546            };
 5547
 5548            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5549            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5550            let mut completions = Vec::new();
 5551            let mut is_incomplete = false;
 5552            if let Some(provider_responses) = provider_responses.await.log_err() {
 5553                if !provider_responses.is_empty() {
 5554                    for response in provider_responses {
 5555                        completions.extend(response.completions);
 5556                        is_incomplete = is_incomplete || response.is_incomplete;
 5557                    }
 5558                    if completion_settings.words == WordsCompletionMode::Fallback {
 5559                        words = Task::ready(BTreeMap::default());
 5560                    }
 5561                }
 5562            }
 5563
 5564            let mut words = words.await;
 5565            if let Some(word_to_exclude) = &word_to_exclude {
 5566                words.remove(word_to_exclude);
 5567            }
 5568            for lsp_completion in &completions {
 5569                words.remove(&lsp_completion.new_text);
 5570            }
 5571            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5572                replace_range: word_replace_range.clone(),
 5573                new_text: word.clone(),
 5574                label: CodeLabel::plain(word, None),
 5575                icon_path: None,
 5576                documentation: None,
 5577                source: CompletionSource::BufferWord {
 5578                    word_range,
 5579                    resolved: false,
 5580                },
 5581                insert_text_mode: Some(InsertTextMode::AS_IS),
 5582                confirm: None,
 5583            }));
 5584
 5585            let menu = if completions.is_empty() {
 5586                None
 5587            } else {
 5588                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5589                    let languages = editor
 5590                        .workspace
 5591                        .as_ref()
 5592                        .and_then(|(workspace, _)| workspace.upgrade())
 5593                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5594                    let menu = CompletionsMenu::new(
 5595                        id,
 5596                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5597                        sort_completions,
 5598                        show_completion_documentation,
 5599                        position,
 5600                        query.clone(),
 5601                        is_incomplete,
 5602                        buffer.clone(),
 5603                        completions.into(),
 5604                        snippet_sort_order,
 5605                        languages,
 5606                        language,
 5607                        cx,
 5608                    );
 5609
 5610                    let query = if filter_completions { query } else { None };
 5611                    let matches_task = if let Some(query) = query {
 5612                        menu.do_async_filtering(query, cx)
 5613                    } else {
 5614                        Task::ready(menu.unfiltered_matches())
 5615                    };
 5616                    (menu, matches_task)
 5617                }) else {
 5618                    return;
 5619                };
 5620
 5621                let matches = matches_task.await;
 5622
 5623                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5624                    // Newer menu already set, so exit.
 5625                    match editor.context_menu.borrow().as_ref() {
 5626                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5627                            if prev_menu.id > id {
 5628                                return;
 5629                            }
 5630                        }
 5631                        _ => {}
 5632                    };
 5633
 5634                    // Only valid to take prev_menu because it the new menu is immediately set
 5635                    // below, or the menu is hidden.
 5636                    match editor.context_menu.borrow_mut().take() {
 5637                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5638                            let position_matches =
 5639                                if prev_menu.initial_position == menu.initial_position {
 5640                                    true
 5641                                } else {
 5642                                    let snapshot = editor.buffer.read(cx).read(cx);
 5643                                    prev_menu.initial_position.to_offset(&snapshot)
 5644                                        == menu.initial_position.to_offset(&snapshot)
 5645                                };
 5646                            if position_matches {
 5647                                // Preserve markdown cache before `set_filter_results` because it will
 5648                                // try to populate the documentation cache.
 5649                                menu.preserve_markdown_cache(prev_menu);
 5650                            }
 5651                        }
 5652                        _ => {}
 5653                    };
 5654
 5655                    menu.set_filter_results(matches, provider, window, cx);
 5656                }) else {
 5657                    return;
 5658                };
 5659
 5660                menu.visible().then_some(menu)
 5661            };
 5662
 5663            editor
 5664                .update_in(cx, |editor, window, cx| {
 5665                    if editor.focus_handle.is_focused(window) {
 5666                        if let Some(menu) = menu {
 5667                            *editor.context_menu.borrow_mut() =
 5668                                Some(CodeContextMenu::Completions(menu));
 5669
 5670                            crate::hover_popover::hide_hover(editor, cx);
 5671                            if editor.show_edit_predictions_in_menu() {
 5672                                editor.update_visible_inline_completion(window, cx);
 5673                            } else {
 5674                                editor.discard_inline_completion(false, cx);
 5675                            }
 5676
 5677                            cx.notify();
 5678                            return;
 5679                        }
 5680                    }
 5681
 5682                    if editor.completion_tasks.len() <= 1 {
 5683                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5684                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5685                        // If it was already hidden and we don't show inline completions in the menu, we should
 5686                        // also show the inline-completion when available.
 5687                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5688                            editor.update_visible_inline_completion(window, cx);
 5689                        }
 5690                    }
 5691                })
 5692                .ok();
 5693        });
 5694
 5695        self.completion_tasks.push((id, task));
 5696    }
 5697
 5698    #[cfg(feature = "test-support")]
 5699    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5700        let menu = self.context_menu.borrow();
 5701        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5702            let completions = menu.completions.borrow();
 5703            Some(completions.to_vec())
 5704        } else {
 5705            None
 5706        }
 5707    }
 5708
 5709    pub fn with_completions_menu_matching_id<R>(
 5710        &self,
 5711        id: CompletionId,
 5712        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5713    ) -> R {
 5714        let mut context_menu = self.context_menu.borrow_mut();
 5715        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5716            return f(None);
 5717        };
 5718        if completions_menu.id != id {
 5719            return f(None);
 5720        }
 5721        f(Some(completions_menu))
 5722    }
 5723
 5724    pub fn confirm_completion(
 5725        &mut self,
 5726        action: &ConfirmCompletion,
 5727        window: &mut Window,
 5728        cx: &mut Context<Self>,
 5729    ) -> Option<Task<Result<()>>> {
 5730        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5731        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5732    }
 5733
 5734    pub fn confirm_completion_insert(
 5735        &mut self,
 5736        _: &ConfirmCompletionInsert,
 5737        window: &mut Window,
 5738        cx: &mut Context<Self>,
 5739    ) -> Option<Task<Result<()>>> {
 5740        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5741        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5742    }
 5743
 5744    pub fn confirm_completion_replace(
 5745        &mut self,
 5746        _: &ConfirmCompletionReplace,
 5747        window: &mut Window,
 5748        cx: &mut Context<Self>,
 5749    ) -> Option<Task<Result<()>>> {
 5750        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5751        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5752    }
 5753
 5754    pub fn compose_completion(
 5755        &mut self,
 5756        action: &ComposeCompletion,
 5757        window: &mut Window,
 5758        cx: &mut Context<Self>,
 5759    ) -> Option<Task<Result<()>>> {
 5760        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5761        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5762    }
 5763
 5764    fn do_completion(
 5765        &mut self,
 5766        item_ix: Option<usize>,
 5767        intent: CompletionIntent,
 5768        window: &mut Window,
 5769        cx: &mut Context<Editor>,
 5770    ) -> Option<Task<Result<()>>> {
 5771        use language::ToOffset as _;
 5772
 5773        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5774        else {
 5775            return None;
 5776        };
 5777
 5778        let candidate_id = {
 5779            let entries = completions_menu.entries.borrow();
 5780            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5781            if self.show_edit_predictions_in_menu() {
 5782                self.discard_inline_completion(true, cx);
 5783            }
 5784            mat.candidate_id
 5785        };
 5786
 5787        let completion = completions_menu
 5788            .completions
 5789            .borrow()
 5790            .get(candidate_id)?
 5791            .clone();
 5792        cx.stop_propagation();
 5793
 5794        let buffer_handle = completions_menu.buffer.clone();
 5795
 5796        let CompletionEdit {
 5797            new_text,
 5798            snippet,
 5799            replace_range,
 5800        } = process_completion_for_edit(
 5801            &completion,
 5802            intent,
 5803            &buffer_handle,
 5804            &completions_menu.initial_position.text_anchor,
 5805            cx,
 5806        );
 5807
 5808        let buffer = buffer_handle.read(cx);
 5809        let snapshot = self.buffer.read(cx).snapshot(cx);
 5810        let newest_anchor = self.selections.newest_anchor();
 5811        let replace_range_multibuffer = {
 5812            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5813            let multibuffer_anchor = snapshot
 5814                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5815                .unwrap()
 5816                ..snapshot
 5817                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5818                    .unwrap();
 5819            multibuffer_anchor.start.to_offset(&snapshot)
 5820                ..multibuffer_anchor.end.to_offset(&snapshot)
 5821        };
 5822        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5823            return None;
 5824        }
 5825
 5826        let old_text = buffer
 5827            .text_for_range(replace_range.clone())
 5828            .collect::<String>();
 5829        let lookbehind = newest_anchor
 5830            .start
 5831            .text_anchor
 5832            .to_offset(buffer)
 5833            .saturating_sub(replace_range.start);
 5834        let lookahead = replace_range
 5835            .end
 5836            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5837        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5838        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5839
 5840        let selections = self.selections.all::<usize>(cx);
 5841        let mut ranges = Vec::new();
 5842        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5843
 5844        for selection in &selections {
 5845            let range = if selection.id == newest_anchor.id {
 5846                replace_range_multibuffer.clone()
 5847            } else {
 5848                let mut range = selection.range();
 5849
 5850                // if prefix is present, don't duplicate it
 5851                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5852                    range.start = range.start.saturating_sub(lookbehind);
 5853
 5854                    // if suffix is also present, mimic the newest cursor and replace it
 5855                    if selection.id != newest_anchor.id
 5856                        && snapshot.contains_str_at(range.end, suffix)
 5857                    {
 5858                        range.end += lookahead;
 5859                    }
 5860                }
 5861                range
 5862            };
 5863
 5864            ranges.push(range.clone());
 5865
 5866            if !self.linked_edit_ranges.is_empty() {
 5867                let start_anchor = snapshot.anchor_before(range.start);
 5868                let end_anchor = snapshot.anchor_after(range.end);
 5869                if let Some(ranges) = self
 5870                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5871                {
 5872                    for (buffer, edits) in ranges {
 5873                        linked_edits
 5874                            .entry(buffer.clone())
 5875                            .or_default()
 5876                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5877                    }
 5878                }
 5879            }
 5880        }
 5881
 5882        let common_prefix_len = old_text
 5883            .chars()
 5884            .zip(new_text.chars())
 5885            .take_while(|(a, b)| a == b)
 5886            .map(|(a, _)| a.len_utf8())
 5887            .sum::<usize>();
 5888
 5889        cx.emit(EditorEvent::InputHandled {
 5890            utf16_range_to_replace: None,
 5891            text: new_text[common_prefix_len..].into(),
 5892        });
 5893
 5894        self.transact(window, cx, |editor, window, cx| {
 5895            if let Some(mut snippet) = snippet {
 5896                snippet.text = new_text.to_string();
 5897                editor
 5898                    .insert_snippet(&ranges, snippet, window, cx)
 5899                    .log_err();
 5900            } else {
 5901                editor.buffer.update(cx, |multi_buffer, cx| {
 5902                    let auto_indent = match completion.insert_text_mode {
 5903                        Some(InsertTextMode::AS_IS) => None,
 5904                        _ => editor.autoindent_mode.clone(),
 5905                    };
 5906                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5907                    multi_buffer.edit(edits, auto_indent, cx);
 5908                });
 5909            }
 5910            for (buffer, edits) in linked_edits {
 5911                buffer.update(cx, |buffer, cx| {
 5912                    let snapshot = buffer.snapshot();
 5913                    let edits = edits
 5914                        .into_iter()
 5915                        .map(|(range, text)| {
 5916                            use text::ToPoint as TP;
 5917                            let end_point = TP::to_point(&range.end, &snapshot);
 5918                            let start_point = TP::to_point(&range.start, &snapshot);
 5919                            (start_point..end_point, text)
 5920                        })
 5921                        .sorted_by_key(|(range, _)| range.start);
 5922                    buffer.edit(edits, None, cx);
 5923                })
 5924            }
 5925
 5926            editor.refresh_inline_completion(true, false, window, cx);
 5927        });
 5928        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), &snapshot);
 5929
 5930        let show_new_completions_on_confirm = completion
 5931            .confirm
 5932            .as_ref()
 5933            .map_or(false, |confirm| confirm(intent, window, cx));
 5934        if show_new_completions_on_confirm {
 5935            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5936        }
 5937
 5938        let provider = self.completion_provider.as_ref()?;
 5939        drop(completion);
 5940        let apply_edits = provider.apply_additional_edits_for_completion(
 5941            buffer_handle,
 5942            completions_menu.completions.clone(),
 5943            candidate_id,
 5944            true,
 5945            cx,
 5946        );
 5947
 5948        let editor_settings = EditorSettings::get_global(cx);
 5949        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5950            // After the code completion is finished, users often want to know what signatures are needed.
 5951            // so we should automatically call signature_help
 5952            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5953        }
 5954
 5955        Some(cx.foreground_executor().spawn(async move {
 5956            apply_edits.await?;
 5957            Ok(())
 5958        }))
 5959    }
 5960
 5961    pub fn toggle_code_actions(
 5962        &mut self,
 5963        action: &ToggleCodeActions,
 5964        window: &mut Window,
 5965        cx: &mut Context<Self>,
 5966    ) {
 5967        let quick_launch = action.quick_launch;
 5968        let mut context_menu = self.context_menu.borrow_mut();
 5969        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5970            if code_actions.deployed_from == action.deployed_from {
 5971                // Toggle if we're selecting the same one
 5972                *context_menu = None;
 5973                cx.notify();
 5974                return;
 5975            } else {
 5976                // Otherwise, clear it and start a new one
 5977                *context_menu = None;
 5978                cx.notify();
 5979            }
 5980        }
 5981        drop(context_menu);
 5982        let snapshot = self.snapshot(window, cx);
 5983        let deployed_from = action.deployed_from.clone();
 5984        let action = action.clone();
 5985        self.completion_tasks.clear();
 5986        self.discard_inline_completion(false, cx);
 5987
 5988        let multibuffer_point = match &action.deployed_from {
 5989            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5990                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5991            }
 5992            _ => self.selections.newest::<Point>(cx).head(),
 5993        };
 5994        let Some((buffer, buffer_row)) = snapshot
 5995            .buffer_snapshot
 5996            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5997            .and_then(|(buffer_snapshot, range)| {
 5998                self.buffer()
 5999                    .read(cx)
 6000                    .buffer(buffer_snapshot.remote_id())
 6001                    .map(|buffer| (buffer, range.start.row))
 6002            })
 6003        else {
 6004            return;
 6005        };
 6006        let buffer_id = buffer.read(cx).remote_id();
 6007        let tasks = self
 6008            .tasks
 6009            .get(&(buffer_id, buffer_row))
 6010            .map(|t| Arc::new(t.to_owned()));
 6011
 6012        if !self.focus_handle.is_focused(window) {
 6013            return;
 6014        }
 6015        let project = self.project.clone();
 6016
 6017        let code_actions_task = match deployed_from {
 6018            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6019            _ => self.code_actions(buffer_row, window, cx),
 6020        };
 6021
 6022        let runnable_task = match deployed_from {
 6023            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6024            _ => {
 6025                let mut task_context_task = Task::ready(None);
 6026                if let Some(tasks) = &tasks {
 6027                    if let Some(project) = project {
 6028                        task_context_task =
 6029                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 6030                    }
 6031                }
 6032
 6033                cx.spawn_in(window, {
 6034                    let buffer = buffer.clone();
 6035                    async move |editor, cx| {
 6036                        let task_context = task_context_task.await;
 6037
 6038                        let resolved_tasks =
 6039                            tasks
 6040                                .zip(task_context.clone())
 6041                                .map(|(tasks, task_context)| ResolvedTasks {
 6042                                    templates: tasks.resolve(&task_context).collect(),
 6043                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6044                                        multibuffer_point.row,
 6045                                        tasks.column,
 6046                                    )),
 6047                                });
 6048                        let debug_scenarios = editor
 6049                            .update(cx, |editor, cx| {
 6050                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6051                            })?
 6052                            .await;
 6053                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6054                    }
 6055                })
 6056            }
 6057        };
 6058
 6059        cx.spawn_in(window, async move |editor, cx| {
 6060            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6061            let code_actions = code_actions_task.await;
 6062            let spawn_straight_away = quick_launch
 6063                && resolved_tasks
 6064                    .as_ref()
 6065                    .map_or(false, |tasks| tasks.templates.len() == 1)
 6066                && code_actions
 6067                    .as_ref()
 6068                    .map_or(true, |actions| actions.is_empty())
 6069                && debug_scenarios.is_empty();
 6070
 6071            editor.update_in(cx, |editor, window, cx| {
 6072                crate::hover_popover::hide_hover(editor, cx);
 6073                let actions = CodeActionContents::new(
 6074                    resolved_tasks,
 6075                    code_actions,
 6076                    debug_scenarios,
 6077                    task_context.unwrap_or_default(),
 6078                );
 6079
 6080                // Don't show the menu if there are no actions available
 6081                if actions.is_empty() {
 6082                    cx.notify();
 6083                    return Task::ready(Ok(()));
 6084                }
 6085
 6086                *editor.context_menu.borrow_mut() =
 6087                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6088                        buffer,
 6089                        actions,
 6090                        selected_item: Default::default(),
 6091                        scroll_handle: UniformListScrollHandle::default(),
 6092                        deployed_from,
 6093                    }));
 6094                cx.notify();
 6095                if spawn_straight_away {
 6096                    if let Some(task) = editor.confirm_code_action(
 6097                        &ConfirmCodeAction { item_ix: Some(0) },
 6098                        window,
 6099                        cx,
 6100                    ) {
 6101                        return task;
 6102                    }
 6103                }
 6104
 6105                Task::ready(Ok(()))
 6106            })
 6107        })
 6108        .detach_and_log_err(cx);
 6109    }
 6110
 6111    fn debug_scenarios(
 6112        &mut self,
 6113        resolved_tasks: &Option<ResolvedTasks>,
 6114        buffer: &Entity<Buffer>,
 6115        cx: &mut App,
 6116    ) -> Task<Vec<task::DebugScenario>> {
 6117        maybe!({
 6118            let project = self.project.as_ref()?;
 6119            let dap_store = project.read(cx).dap_store();
 6120            let mut scenarios = vec![];
 6121            let resolved_tasks = resolved_tasks.as_ref()?;
 6122            let buffer = buffer.read(cx);
 6123            let language = buffer.language()?;
 6124            let file = buffer.file();
 6125            let debug_adapter = language_settings(language.name().into(), file, cx)
 6126                .debuggers
 6127                .first()
 6128                .map(SharedString::from)
 6129                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6130
 6131            dap_store.update(cx, |dap_store, cx| {
 6132                for (_, task) in &resolved_tasks.templates {
 6133                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6134                        task.original_task().clone(),
 6135                        debug_adapter.clone().into(),
 6136                        task.display_label().to_owned().into(),
 6137                        cx,
 6138                    );
 6139                    scenarios.push(maybe_scenario);
 6140                }
 6141            });
 6142            Some(cx.background_spawn(async move {
 6143                let scenarios = futures::future::join_all(scenarios)
 6144                    .await
 6145                    .into_iter()
 6146                    .flatten()
 6147                    .collect::<Vec<_>>();
 6148                scenarios
 6149            }))
 6150        })
 6151        .unwrap_or_else(|| Task::ready(vec![]))
 6152    }
 6153
 6154    fn code_actions(
 6155        &mut self,
 6156        buffer_row: u32,
 6157        window: &mut Window,
 6158        cx: &mut Context<Self>,
 6159    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6160        let mut task = self.code_actions_task.take();
 6161        cx.spawn_in(window, async move |editor, cx| {
 6162            while let Some(prev_task) = task {
 6163                prev_task.await.log_err();
 6164                task = editor
 6165                    .update(cx, |this, _| this.code_actions_task.take())
 6166                    .ok()?;
 6167            }
 6168
 6169            editor
 6170                .update(cx, |editor, cx| {
 6171                    editor
 6172                        .available_code_actions
 6173                        .clone()
 6174                        .and_then(|(location, code_actions)| {
 6175                            let snapshot = location.buffer.read(cx).snapshot();
 6176                            let point_range = location.range.to_point(&snapshot);
 6177                            let point_range = point_range.start.row..=point_range.end.row;
 6178                            if point_range.contains(&buffer_row) {
 6179                                Some(code_actions)
 6180                            } else {
 6181                                None
 6182                            }
 6183                        })
 6184                })
 6185                .ok()
 6186                .flatten()
 6187        })
 6188    }
 6189
 6190    pub fn confirm_code_action(
 6191        &mut self,
 6192        action: &ConfirmCodeAction,
 6193        window: &mut Window,
 6194        cx: &mut Context<Self>,
 6195    ) -> Option<Task<Result<()>>> {
 6196        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6197
 6198        let actions_menu =
 6199            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6200                menu
 6201            } else {
 6202                return None;
 6203            };
 6204
 6205        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6206        let action = actions_menu.actions.get(action_ix)?;
 6207        let title = action.label();
 6208        let buffer = actions_menu.buffer;
 6209        let workspace = self.workspace()?;
 6210
 6211        match action {
 6212            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6213                workspace.update(cx, |workspace, cx| {
 6214                    workspace.schedule_resolved_task(
 6215                        task_source_kind,
 6216                        resolved_task,
 6217                        false,
 6218                        window,
 6219                        cx,
 6220                    );
 6221
 6222                    Some(Task::ready(Ok(())))
 6223                })
 6224            }
 6225            CodeActionsItem::CodeAction {
 6226                excerpt_id,
 6227                action,
 6228                provider,
 6229            } => {
 6230                let apply_code_action =
 6231                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6232                let workspace = workspace.downgrade();
 6233                Some(cx.spawn_in(window, async move |editor, cx| {
 6234                    let project_transaction = apply_code_action.await?;
 6235                    Self::open_project_transaction(
 6236                        &editor,
 6237                        workspace,
 6238                        project_transaction,
 6239                        title,
 6240                        cx,
 6241                    )
 6242                    .await
 6243                }))
 6244            }
 6245            CodeActionsItem::DebugScenario(scenario) => {
 6246                let context = actions_menu.actions.context.clone();
 6247
 6248                workspace.update(cx, |workspace, cx| {
 6249                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6250                    workspace.start_debug_session(
 6251                        scenario,
 6252                        context,
 6253                        Some(buffer),
 6254                        None,
 6255                        window,
 6256                        cx,
 6257                    );
 6258                });
 6259                Some(Task::ready(Ok(())))
 6260            }
 6261        }
 6262    }
 6263
 6264    pub async fn open_project_transaction(
 6265        this: &WeakEntity<Editor>,
 6266        workspace: WeakEntity<Workspace>,
 6267        transaction: ProjectTransaction,
 6268        title: String,
 6269        cx: &mut AsyncWindowContext,
 6270    ) -> Result<()> {
 6271        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6272        cx.update(|_, cx| {
 6273            entries.sort_unstable_by_key(|(buffer, _)| {
 6274                buffer.read(cx).file().map(|f| f.path().clone())
 6275            });
 6276        })?;
 6277
 6278        // If the project transaction's edits are all contained within this editor, then
 6279        // avoid opening a new editor to display them.
 6280
 6281        if let Some((buffer, transaction)) = entries.first() {
 6282            if entries.len() == 1 {
 6283                let excerpt = this.update(cx, |editor, cx| {
 6284                    editor
 6285                        .buffer()
 6286                        .read(cx)
 6287                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6288                })?;
 6289                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6290                    if excerpted_buffer == *buffer {
 6291                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6292                            let excerpt_range = excerpt_range.to_offset(buffer);
 6293                            buffer
 6294                                .edited_ranges_for_transaction::<usize>(transaction)
 6295                                .all(|range| {
 6296                                    excerpt_range.start <= range.start
 6297                                        && excerpt_range.end >= range.end
 6298                                })
 6299                        })?;
 6300
 6301                        if all_edits_within_excerpt {
 6302                            return Ok(());
 6303                        }
 6304                    }
 6305                }
 6306            }
 6307        } else {
 6308            return Ok(());
 6309        }
 6310
 6311        let mut ranges_to_highlight = Vec::new();
 6312        let excerpt_buffer = cx.new(|cx| {
 6313            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6314            for (buffer_handle, transaction) in &entries {
 6315                let edited_ranges = buffer_handle
 6316                    .read(cx)
 6317                    .edited_ranges_for_transaction::<Point>(transaction)
 6318                    .collect::<Vec<_>>();
 6319                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6320                    PathKey::for_buffer(buffer_handle, cx),
 6321                    buffer_handle.clone(),
 6322                    edited_ranges,
 6323                    DEFAULT_MULTIBUFFER_CONTEXT,
 6324                    cx,
 6325                );
 6326
 6327                ranges_to_highlight.extend(ranges);
 6328            }
 6329            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6330            multibuffer
 6331        })?;
 6332
 6333        workspace.update_in(cx, |workspace, window, cx| {
 6334            let project = workspace.project().clone();
 6335            let editor =
 6336                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6337            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6338            editor.update(cx, |editor, cx| {
 6339                editor.highlight_background::<Self>(
 6340                    &ranges_to_highlight,
 6341                    |theme| theme.colors().editor_highlighted_line_background,
 6342                    cx,
 6343                );
 6344            });
 6345        })?;
 6346
 6347        Ok(())
 6348    }
 6349
 6350    pub fn clear_code_action_providers(&mut self) {
 6351        self.code_action_providers.clear();
 6352        self.available_code_actions.take();
 6353    }
 6354
 6355    pub fn add_code_action_provider(
 6356        &mut self,
 6357        provider: Rc<dyn CodeActionProvider>,
 6358        window: &mut Window,
 6359        cx: &mut Context<Self>,
 6360    ) {
 6361        if self
 6362            .code_action_providers
 6363            .iter()
 6364            .any(|existing_provider| existing_provider.id() == provider.id())
 6365        {
 6366            return;
 6367        }
 6368
 6369        self.code_action_providers.push(provider);
 6370        self.refresh_code_actions(window, cx);
 6371    }
 6372
 6373    pub fn remove_code_action_provider(
 6374        &mut self,
 6375        id: Arc<str>,
 6376        window: &mut Window,
 6377        cx: &mut Context<Self>,
 6378    ) {
 6379        self.code_action_providers
 6380            .retain(|provider| provider.id() != id);
 6381        self.refresh_code_actions(window, cx);
 6382    }
 6383
 6384    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6385        !self.code_action_providers.is_empty()
 6386            && EditorSettings::get_global(cx).toolbar.code_actions
 6387    }
 6388
 6389    pub fn has_available_code_actions(&self) -> bool {
 6390        self.available_code_actions
 6391            .as_ref()
 6392            .is_some_and(|(_, actions)| !actions.is_empty())
 6393    }
 6394
 6395    fn render_inline_code_actions(
 6396        &self,
 6397        icon_size: ui::IconSize,
 6398        display_row: DisplayRow,
 6399        is_active: bool,
 6400        cx: &mut Context<Self>,
 6401    ) -> AnyElement {
 6402        let show_tooltip = !self.context_menu_visible();
 6403        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6404            .icon_size(icon_size)
 6405            .shape(ui::IconButtonShape::Square)
 6406            .icon_color(ui::Color::Hidden)
 6407            .toggle_state(is_active)
 6408            .when(show_tooltip, |this| {
 6409                this.tooltip({
 6410                    let focus_handle = self.focus_handle.clone();
 6411                    move |window, cx| {
 6412                        Tooltip::for_action_in(
 6413                            "Toggle Code Actions",
 6414                            &ToggleCodeActions {
 6415                                deployed_from: None,
 6416                                quick_launch: false,
 6417                            },
 6418                            &focus_handle,
 6419                            window,
 6420                            cx,
 6421                        )
 6422                    }
 6423                })
 6424            })
 6425            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6426                window.focus(&editor.focus_handle(cx));
 6427                editor.toggle_code_actions(
 6428                    &crate::actions::ToggleCodeActions {
 6429                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6430                            display_row,
 6431                        )),
 6432                        quick_launch: false,
 6433                    },
 6434                    window,
 6435                    cx,
 6436                );
 6437            }))
 6438            .into_any_element()
 6439    }
 6440
 6441    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6442        &self.context_menu
 6443    }
 6444
 6445    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6446        let newest_selection = self.selections.newest_anchor().clone();
 6447        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6448        let buffer = self.buffer.read(cx);
 6449        if newest_selection.head().diff_base_anchor.is_some() {
 6450            return None;
 6451        }
 6452        let (start_buffer, start) =
 6453            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6454        let (end_buffer, end) =
 6455            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6456        if start_buffer != end_buffer {
 6457            return None;
 6458        }
 6459
 6460        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6461            cx.background_executor()
 6462                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6463                .await;
 6464
 6465            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6466                let providers = this.code_action_providers.clone();
 6467                let tasks = this
 6468                    .code_action_providers
 6469                    .iter()
 6470                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6471                    .collect::<Vec<_>>();
 6472                (providers, tasks)
 6473            })?;
 6474
 6475            let mut actions = Vec::new();
 6476            for (provider, provider_actions) in
 6477                providers.into_iter().zip(future::join_all(tasks).await)
 6478            {
 6479                if let Some(provider_actions) = provider_actions.log_err() {
 6480                    actions.extend(provider_actions.into_iter().map(|action| {
 6481                        AvailableCodeAction {
 6482                            excerpt_id: newest_selection.start.excerpt_id,
 6483                            action,
 6484                            provider: provider.clone(),
 6485                        }
 6486                    }));
 6487                }
 6488            }
 6489
 6490            this.update(cx, |this, cx| {
 6491                this.available_code_actions = if actions.is_empty() {
 6492                    None
 6493                } else {
 6494                    Some((
 6495                        Location {
 6496                            buffer: start_buffer,
 6497                            range: start..end,
 6498                        },
 6499                        actions.into(),
 6500                    ))
 6501                };
 6502                cx.notify();
 6503            })
 6504        }));
 6505        None
 6506    }
 6507
 6508    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6509        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6510            self.show_git_blame_inline = false;
 6511
 6512            self.show_git_blame_inline_delay_task =
 6513                Some(cx.spawn_in(window, async move |this, cx| {
 6514                    cx.background_executor().timer(delay).await;
 6515
 6516                    this.update(cx, |this, cx| {
 6517                        this.show_git_blame_inline = true;
 6518                        cx.notify();
 6519                    })
 6520                    .log_err();
 6521                }));
 6522        }
 6523    }
 6524
 6525    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6526        let snapshot = self.snapshot(window, cx);
 6527        let cursor = self.selections.newest::<Point>(cx).head();
 6528        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6529        else {
 6530            return;
 6531        };
 6532
 6533        let Some(blame) = self.blame.as_ref() else {
 6534            return;
 6535        };
 6536
 6537        let row_info = RowInfo {
 6538            buffer_id: Some(buffer.remote_id()),
 6539            buffer_row: Some(point.row),
 6540            ..Default::default()
 6541        };
 6542        let Some(blame_entry) = blame
 6543            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6544            .flatten()
 6545        else {
 6546            return;
 6547        };
 6548
 6549        let anchor = self.selections.newest_anchor().head();
 6550        let position = self.to_pixel_point(anchor, &snapshot, window);
 6551        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6552            self.show_blame_popover(&blame_entry, position + last_bounds.origin, true, cx);
 6553        };
 6554    }
 6555
 6556    fn show_blame_popover(
 6557        &mut self,
 6558        blame_entry: &BlameEntry,
 6559        position: gpui::Point<Pixels>,
 6560        ignore_timeout: bool,
 6561        cx: &mut Context<Self>,
 6562    ) {
 6563        if let Some(state) = &mut self.inline_blame_popover {
 6564            state.hide_task.take();
 6565        } else {
 6566            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6567            let blame_entry = blame_entry.clone();
 6568            let show_task = cx.spawn(async move |editor, cx| {
 6569                if !ignore_timeout {
 6570                    cx.background_executor()
 6571                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6572                        .await;
 6573                }
 6574                editor
 6575                    .update(cx, |editor, cx| {
 6576                        editor.inline_blame_popover_show_task.take();
 6577                        let Some(blame) = editor.blame.as_ref() else {
 6578                            return;
 6579                        };
 6580                        let blame = blame.read(cx);
 6581                        let details = blame.details_for_entry(&blame_entry);
 6582                        let markdown = cx.new(|cx| {
 6583                            Markdown::new(
 6584                                details
 6585                                    .as_ref()
 6586                                    .map(|message| message.message.clone())
 6587                                    .unwrap_or_default(),
 6588                                None,
 6589                                None,
 6590                                cx,
 6591                            )
 6592                        });
 6593                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6594                            position,
 6595                            hide_task: None,
 6596                            popover_bounds: None,
 6597                            popover_state: InlineBlamePopoverState {
 6598                                scroll_handle: ScrollHandle::new(),
 6599                                commit_message: details,
 6600                                markdown,
 6601                            },
 6602                            keyboard_grace: ignore_timeout,
 6603                        });
 6604                        cx.notify();
 6605                    })
 6606                    .ok();
 6607            });
 6608            self.inline_blame_popover_show_task = Some(show_task);
 6609        }
 6610    }
 6611
 6612    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6613        self.inline_blame_popover_show_task.take();
 6614        if let Some(state) = &mut self.inline_blame_popover {
 6615            let hide_task = cx.spawn(async move |editor, cx| {
 6616                cx.background_executor()
 6617                    .timer(std::time::Duration::from_millis(100))
 6618                    .await;
 6619                editor
 6620                    .update(cx, |editor, cx| {
 6621                        editor.inline_blame_popover.take();
 6622                        cx.notify();
 6623                    })
 6624                    .ok();
 6625            });
 6626            state.hide_task = Some(hide_task);
 6627        }
 6628    }
 6629
 6630    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6631        if self.pending_rename.is_some() {
 6632            return None;
 6633        }
 6634
 6635        let provider = self.semantics_provider.clone()?;
 6636        let buffer = self.buffer.read(cx);
 6637        let newest_selection = self.selections.newest_anchor().clone();
 6638        let cursor_position = newest_selection.head();
 6639        let (cursor_buffer, cursor_buffer_position) =
 6640            buffer.text_anchor_for_position(cursor_position, cx)?;
 6641        let (tail_buffer, tail_buffer_position) =
 6642            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6643        if cursor_buffer != tail_buffer {
 6644            return None;
 6645        }
 6646
 6647        let snapshot = cursor_buffer.read(cx).snapshot();
 6648        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6649        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6650        if start_word_range != end_word_range {
 6651            self.document_highlights_task.take();
 6652            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6653            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6654            return None;
 6655        }
 6656
 6657        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6658        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6659            cx.background_executor()
 6660                .timer(Duration::from_millis(debounce))
 6661                .await;
 6662
 6663            let highlights = if let Some(highlights) = cx
 6664                .update(|cx| {
 6665                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6666                })
 6667                .ok()
 6668                .flatten()
 6669            {
 6670                highlights.await.log_err()
 6671            } else {
 6672                None
 6673            };
 6674
 6675            if let Some(highlights) = highlights {
 6676                this.update(cx, |this, cx| {
 6677                    if this.pending_rename.is_some() {
 6678                        return;
 6679                    }
 6680
 6681                    let buffer_id = cursor_position.buffer_id;
 6682                    let buffer = this.buffer.read(cx);
 6683                    if !buffer
 6684                        .text_anchor_for_position(cursor_position, cx)
 6685                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6686                    {
 6687                        return;
 6688                    }
 6689
 6690                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6691                    let mut write_ranges = Vec::new();
 6692                    let mut read_ranges = Vec::new();
 6693                    for highlight in highlights {
 6694                        for (excerpt_id, excerpt_range) in
 6695                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6696                        {
 6697                            let start = highlight
 6698                                .range
 6699                                .start
 6700                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6701                            let end = highlight
 6702                                .range
 6703                                .end
 6704                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6705                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6706                                continue;
 6707                            }
 6708
 6709                            let range = Anchor {
 6710                                buffer_id,
 6711                                excerpt_id,
 6712                                text_anchor: start,
 6713                                diff_base_anchor: None,
 6714                            }..Anchor {
 6715                                buffer_id,
 6716                                excerpt_id,
 6717                                text_anchor: end,
 6718                                diff_base_anchor: None,
 6719                            };
 6720                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6721                                write_ranges.push(range);
 6722                            } else {
 6723                                read_ranges.push(range);
 6724                            }
 6725                        }
 6726                    }
 6727
 6728                    this.highlight_background::<DocumentHighlightRead>(
 6729                        &read_ranges,
 6730                        |theme| theme.colors().editor_document_highlight_read_background,
 6731                        cx,
 6732                    );
 6733                    this.highlight_background::<DocumentHighlightWrite>(
 6734                        &write_ranges,
 6735                        |theme| theme.colors().editor_document_highlight_write_background,
 6736                        cx,
 6737                    );
 6738                    cx.notify();
 6739                })
 6740                .log_err();
 6741            }
 6742        }));
 6743        None
 6744    }
 6745
 6746    fn prepare_highlight_query_from_selection(
 6747        &mut self,
 6748        cx: &mut Context<Editor>,
 6749    ) -> Option<(String, Range<Anchor>)> {
 6750        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6751            return None;
 6752        }
 6753        if !EditorSettings::get_global(cx).selection_highlight {
 6754            return None;
 6755        }
 6756        if self.selections.count() != 1 || self.selections.line_mode {
 6757            return None;
 6758        }
 6759        let selection = self.selections.newest::<Point>(cx);
 6760        if selection.is_empty() || selection.start.row != selection.end.row {
 6761            return None;
 6762        }
 6763        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6764        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6765        let query = multi_buffer_snapshot
 6766            .text_for_range(selection_anchor_range.clone())
 6767            .collect::<String>();
 6768        if query.trim().is_empty() {
 6769            return None;
 6770        }
 6771        Some((query, selection_anchor_range))
 6772    }
 6773
 6774    fn update_selection_occurrence_highlights(
 6775        &mut self,
 6776        query_text: String,
 6777        query_range: Range<Anchor>,
 6778        multi_buffer_range_to_query: Range<Point>,
 6779        use_debounce: bool,
 6780        window: &mut Window,
 6781        cx: &mut Context<Editor>,
 6782    ) -> Task<()> {
 6783        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6784        cx.spawn_in(window, async move |editor, cx| {
 6785            if use_debounce {
 6786                cx.background_executor()
 6787                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6788                    .await;
 6789            }
 6790            let match_task = cx.background_spawn(async move {
 6791                let buffer_ranges = multi_buffer_snapshot
 6792                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6793                    .into_iter()
 6794                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6795                let mut match_ranges = Vec::new();
 6796                let Ok(regex) = project::search::SearchQuery::text(
 6797                    query_text.clone(),
 6798                    false,
 6799                    false,
 6800                    false,
 6801                    Default::default(),
 6802                    Default::default(),
 6803                    false,
 6804                    None,
 6805                ) else {
 6806                    return Vec::default();
 6807                };
 6808                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6809                    match_ranges.extend(
 6810                        regex
 6811                            .search(&buffer_snapshot, Some(search_range.clone()))
 6812                            .await
 6813                            .into_iter()
 6814                            .filter_map(|match_range| {
 6815                                let match_start = buffer_snapshot
 6816                                    .anchor_after(search_range.start + match_range.start);
 6817                                let match_end = buffer_snapshot
 6818                                    .anchor_before(search_range.start + match_range.end);
 6819                                let match_anchor_range = Anchor::range_in_buffer(
 6820                                    excerpt_id,
 6821                                    buffer_snapshot.remote_id(),
 6822                                    match_start..match_end,
 6823                                );
 6824                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6825                            }),
 6826                    );
 6827                }
 6828                match_ranges
 6829            });
 6830            let match_ranges = match_task.await;
 6831            editor
 6832                .update_in(cx, |editor, _, cx| {
 6833                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6834                    if !match_ranges.is_empty() {
 6835                        editor.highlight_background::<SelectedTextHighlight>(
 6836                            &match_ranges,
 6837                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6838                            cx,
 6839                        )
 6840                    }
 6841                })
 6842                .log_err();
 6843        })
 6844    }
 6845
 6846    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6847        struct NewlineFold;
 6848        let type_id = std::any::TypeId::of::<NewlineFold>();
 6849        if !self.mode.is_single_line() {
 6850            return;
 6851        }
 6852        let snapshot = self.snapshot(window, cx);
 6853        if snapshot.buffer_snapshot.max_point().row == 0 {
 6854            return;
 6855        }
 6856        let task = cx.background_spawn(async move {
 6857            let new_newlines = snapshot
 6858                .buffer_chars_at(0)
 6859                .filter_map(|(c, i)| {
 6860                    if c == '\n' {
 6861                        Some(
 6862                            snapshot.buffer_snapshot.anchor_after(i)
 6863                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6864                        )
 6865                    } else {
 6866                        None
 6867                    }
 6868                })
 6869                .collect::<Vec<_>>();
 6870            let existing_newlines = snapshot
 6871                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6872                .filter_map(|fold| {
 6873                    if fold.placeholder.type_tag == Some(type_id) {
 6874                        Some(fold.range.start..fold.range.end)
 6875                    } else {
 6876                        None
 6877                    }
 6878                })
 6879                .collect::<Vec<_>>();
 6880
 6881            (new_newlines, existing_newlines)
 6882        });
 6883        self.folding_newlines = cx.spawn(async move |this, cx| {
 6884            let (new_newlines, existing_newlines) = task.await;
 6885            if new_newlines == existing_newlines {
 6886                return;
 6887            }
 6888            let placeholder = FoldPlaceholder {
 6889                render: Arc::new(move |_, _, cx| {
 6890                    div()
 6891                        .bg(cx.theme().status().hint_background)
 6892                        .border_b_1()
 6893                        .size_full()
 6894                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6895                        .border_color(cx.theme().status().hint)
 6896                        .child("\\n")
 6897                        .into_any()
 6898                }),
 6899                constrain_width: false,
 6900                merge_adjacent: false,
 6901                type_tag: Some(type_id),
 6902            };
 6903            let creases = new_newlines
 6904                .into_iter()
 6905                .map(|range| Crease::simple(range, placeholder.clone()))
 6906                .collect();
 6907            this.update(cx, |this, cx| {
 6908                this.display_map.update(cx, |display_map, cx| {
 6909                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6910                    display_map.fold(creases, cx);
 6911                });
 6912            })
 6913            .ok();
 6914        });
 6915    }
 6916
 6917    fn refresh_selected_text_highlights(
 6918        &mut self,
 6919        on_buffer_edit: bool,
 6920        window: &mut Window,
 6921        cx: &mut Context<Editor>,
 6922    ) {
 6923        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6924        else {
 6925            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6926            self.quick_selection_highlight_task.take();
 6927            self.debounced_selection_highlight_task.take();
 6928            return;
 6929        };
 6930        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6931        if on_buffer_edit
 6932            || self
 6933                .quick_selection_highlight_task
 6934                .as_ref()
 6935                .map_or(true, |(prev_anchor_range, _)| {
 6936                    prev_anchor_range != &query_range
 6937                })
 6938        {
 6939            let multi_buffer_visible_start = self
 6940                .scroll_manager
 6941                .anchor()
 6942                .anchor
 6943                .to_point(&multi_buffer_snapshot);
 6944            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6945                multi_buffer_visible_start
 6946                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6947                Bias::Left,
 6948            );
 6949            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6950            self.quick_selection_highlight_task = Some((
 6951                query_range.clone(),
 6952                self.update_selection_occurrence_highlights(
 6953                    query_text.clone(),
 6954                    query_range.clone(),
 6955                    multi_buffer_visible_range,
 6956                    false,
 6957                    window,
 6958                    cx,
 6959                ),
 6960            ));
 6961        }
 6962        if on_buffer_edit
 6963            || self
 6964                .debounced_selection_highlight_task
 6965                .as_ref()
 6966                .map_or(true, |(prev_anchor_range, _)| {
 6967                    prev_anchor_range != &query_range
 6968                })
 6969        {
 6970            let multi_buffer_start = multi_buffer_snapshot
 6971                .anchor_before(0)
 6972                .to_point(&multi_buffer_snapshot);
 6973            let multi_buffer_end = multi_buffer_snapshot
 6974                .anchor_after(multi_buffer_snapshot.len())
 6975                .to_point(&multi_buffer_snapshot);
 6976            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6977            self.debounced_selection_highlight_task = Some((
 6978                query_range.clone(),
 6979                self.update_selection_occurrence_highlights(
 6980                    query_text,
 6981                    query_range,
 6982                    multi_buffer_full_range,
 6983                    true,
 6984                    window,
 6985                    cx,
 6986                ),
 6987            ));
 6988        }
 6989    }
 6990
 6991    pub fn refresh_inline_completion(
 6992        &mut self,
 6993        debounce: bool,
 6994        user_requested: bool,
 6995        window: &mut Window,
 6996        cx: &mut Context<Self>,
 6997    ) -> Option<()> {
 6998        let provider = self.edit_prediction_provider()?;
 6999        let cursor = self.selections.newest_anchor().head();
 7000        let (buffer, cursor_buffer_position) =
 7001            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7002
 7003        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7004            self.discard_inline_completion(false, cx);
 7005            return None;
 7006        }
 7007
 7008        if !user_requested
 7009            && (!self.should_show_edit_predictions()
 7010                || !self.is_focused(window)
 7011                || buffer.read(cx).is_empty())
 7012        {
 7013            self.discard_inline_completion(false, cx);
 7014            return None;
 7015        }
 7016
 7017        self.update_visible_inline_completion(window, cx);
 7018        provider.refresh(
 7019            self.project.clone(),
 7020            buffer,
 7021            cursor_buffer_position,
 7022            debounce,
 7023            cx,
 7024        );
 7025        Some(())
 7026    }
 7027
 7028    fn show_edit_predictions_in_menu(&self) -> bool {
 7029        match self.edit_prediction_settings {
 7030            EditPredictionSettings::Disabled => false,
 7031            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7032        }
 7033    }
 7034
 7035    pub fn edit_predictions_enabled(&self) -> bool {
 7036        match self.edit_prediction_settings {
 7037            EditPredictionSettings::Disabled => false,
 7038            EditPredictionSettings::Enabled { .. } => true,
 7039        }
 7040    }
 7041
 7042    fn edit_prediction_requires_modifier(&self) -> bool {
 7043        match self.edit_prediction_settings {
 7044            EditPredictionSettings::Disabled => false,
 7045            EditPredictionSettings::Enabled {
 7046                preview_requires_modifier,
 7047                ..
 7048            } => preview_requires_modifier,
 7049        }
 7050    }
 7051
 7052    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7053        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7054            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7055        } else {
 7056            let selection = self.selections.newest_anchor();
 7057            let cursor = selection.head();
 7058
 7059            if let Some((buffer, cursor_buffer_position)) =
 7060                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7061            {
 7062                self.edit_prediction_settings =
 7063                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7064            }
 7065        }
 7066    }
 7067
 7068    fn edit_prediction_settings_at_position(
 7069        &self,
 7070        buffer: &Entity<Buffer>,
 7071        buffer_position: language::Anchor,
 7072        cx: &App,
 7073    ) -> EditPredictionSettings {
 7074        if !self.mode.is_full()
 7075            || !self.show_inline_completions_override.unwrap_or(true)
 7076            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 7077        {
 7078            return EditPredictionSettings::Disabled;
 7079        }
 7080
 7081        let buffer = buffer.read(cx);
 7082
 7083        let file = buffer.file();
 7084
 7085        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7086            return EditPredictionSettings::Disabled;
 7087        };
 7088
 7089        let by_provider = matches!(
 7090            self.menu_inline_completions_policy,
 7091            MenuInlineCompletionsPolicy::ByProvider
 7092        );
 7093
 7094        let show_in_menu = by_provider
 7095            && self
 7096                .edit_prediction_provider
 7097                .as_ref()
 7098                .map_or(false, |provider| {
 7099                    provider.provider.show_completions_in_menu()
 7100                });
 7101
 7102        let preview_requires_modifier =
 7103            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7104
 7105        EditPredictionSettings::Enabled {
 7106            show_in_menu,
 7107            preview_requires_modifier,
 7108        }
 7109    }
 7110
 7111    fn should_show_edit_predictions(&self) -> bool {
 7112        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7113    }
 7114
 7115    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7116        matches!(
 7117            self.edit_prediction_preview,
 7118            EditPredictionPreview::Active { .. }
 7119        )
 7120    }
 7121
 7122    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7123        let cursor = self.selections.newest_anchor().head();
 7124        if let Some((buffer, cursor_position)) =
 7125            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7126        {
 7127            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7128        } else {
 7129            false
 7130        }
 7131    }
 7132
 7133    pub fn supports_minimap(&self, cx: &App) -> bool {
 7134        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7135    }
 7136
 7137    fn edit_predictions_enabled_in_buffer(
 7138        &self,
 7139        buffer: &Entity<Buffer>,
 7140        buffer_position: language::Anchor,
 7141        cx: &App,
 7142    ) -> bool {
 7143        maybe!({
 7144            if self.read_only(cx) {
 7145                return Some(false);
 7146            }
 7147            let provider = self.edit_prediction_provider()?;
 7148            if !provider.is_enabled(&buffer, buffer_position, cx) {
 7149                return Some(false);
 7150            }
 7151            let buffer = buffer.read(cx);
 7152            let Some(file) = buffer.file() else {
 7153                return Some(true);
 7154            };
 7155            let settings = all_language_settings(Some(file), cx);
 7156            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7157        })
 7158        .unwrap_or(false)
 7159    }
 7160
 7161    fn cycle_inline_completion(
 7162        &mut self,
 7163        direction: Direction,
 7164        window: &mut Window,
 7165        cx: &mut Context<Self>,
 7166    ) -> Option<()> {
 7167        let provider = self.edit_prediction_provider()?;
 7168        let cursor = self.selections.newest_anchor().head();
 7169        let (buffer, cursor_buffer_position) =
 7170            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7171        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7172            return None;
 7173        }
 7174
 7175        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7176        self.update_visible_inline_completion(window, cx);
 7177
 7178        Some(())
 7179    }
 7180
 7181    pub fn show_inline_completion(
 7182        &mut self,
 7183        _: &ShowEditPrediction,
 7184        window: &mut Window,
 7185        cx: &mut Context<Self>,
 7186    ) {
 7187        if !self.has_active_inline_completion() {
 7188            self.refresh_inline_completion(false, true, window, cx);
 7189            return;
 7190        }
 7191
 7192        self.update_visible_inline_completion(window, cx);
 7193    }
 7194
 7195    pub fn display_cursor_names(
 7196        &mut self,
 7197        _: &DisplayCursorNames,
 7198        window: &mut Window,
 7199        cx: &mut Context<Self>,
 7200    ) {
 7201        self.show_cursor_names(window, cx);
 7202    }
 7203
 7204    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7205        self.show_cursor_names = true;
 7206        cx.notify();
 7207        cx.spawn_in(window, async move |this, cx| {
 7208            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7209            this.update(cx, |this, cx| {
 7210                this.show_cursor_names = false;
 7211                cx.notify()
 7212            })
 7213            .ok()
 7214        })
 7215        .detach();
 7216    }
 7217
 7218    pub fn next_edit_prediction(
 7219        &mut self,
 7220        _: &NextEditPrediction,
 7221        window: &mut Window,
 7222        cx: &mut Context<Self>,
 7223    ) {
 7224        if self.has_active_inline_completion() {
 7225            self.cycle_inline_completion(Direction::Next, window, cx);
 7226        } else {
 7227            let is_copilot_disabled = self
 7228                .refresh_inline_completion(false, true, window, cx)
 7229                .is_none();
 7230            if is_copilot_disabled {
 7231                cx.propagate();
 7232            }
 7233        }
 7234    }
 7235
 7236    pub fn previous_edit_prediction(
 7237        &mut self,
 7238        _: &PreviousEditPrediction,
 7239        window: &mut Window,
 7240        cx: &mut Context<Self>,
 7241    ) {
 7242        if self.has_active_inline_completion() {
 7243            self.cycle_inline_completion(Direction::Prev, window, cx);
 7244        } else {
 7245            let is_copilot_disabled = self
 7246                .refresh_inline_completion(false, true, window, cx)
 7247                .is_none();
 7248            if is_copilot_disabled {
 7249                cx.propagate();
 7250            }
 7251        }
 7252    }
 7253
 7254    pub fn accept_edit_prediction(
 7255        &mut self,
 7256        _: &AcceptEditPrediction,
 7257        window: &mut Window,
 7258        cx: &mut Context<Self>,
 7259    ) {
 7260        if self.show_edit_predictions_in_menu() {
 7261            self.hide_context_menu(window, cx);
 7262        }
 7263
 7264        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7265            return;
 7266        };
 7267
 7268        self.report_inline_completion_event(
 7269            active_inline_completion.completion_id.clone(),
 7270            true,
 7271            cx,
 7272        );
 7273
 7274        match &active_inline_completion.completion {
 7275            InlineCompletion::Move { target, .. } => {
 7276                let target = *target;
 7277
 7278                if let Some(position_map) = &self.last_position_map {
 7279                    if position_map
 7280                        .visible_row_range
 7281                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7282                        || !self.edit_prediction_requires_modifier()
 7283                    {
 7284                        self.unfold_ranges(&[target..target], true, false, cx);
 7285                        // Note that this is also done in vim's handler of the Tab action.
 7286                        self.change_selections(
 7287                            SelectionEffects::scroll(Autoscroll::newest()),
 7288                            window,
 7289                            cx,
 7290                            |selections| {
 7291                                selections.select_anchor_ranges([target..target]);
 7292                            },
 7293                        );
 7294                        self.clear_row_highlights::<EditPredictionPreview>();
 7295
 7296                        self.edit_prediction_preview
 7297                            .set_previous_scroll_position(None);
 7298                    } else {
 7299                        self.edit_prediction_preview
 7300                            .set_previous_scroll_position(Some(
 7301                                position_map.snapshot.scroll_anchor,
 7302                            ));
 7303
 7304                        self.highlight_rows::<EditPredictionPreview>(
 7305                            target..target,
 7306                            cx.theme().colors().editor_highlighted_line_background,
 7307                            RowHighlightOptions {
 7308                                autoscroll: true,
 7309                                ..Default::default()
 7310                            },
 7311                            cx,
 7312                        );
 7313                        self.request_autoscroll(Autoscroll::fit(), cx);
 7314                    }
 7315                }
 7316            }
 7317            InlineCompletion::Edit { edits, .. } => {
 7318                if let Some(provider) = self.edit_prediction_provider() {
 7319                    provider.accept(cx);
 7320                }
 7321
 7322                // Store the transaction ID and selections before applying the edit
 7323                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7324
 7325                let snapshot = self.buffer.read(cx).snapshot(cx);
 7326                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7327
 7328                self.buffer.update(cx, |buffer, cx| {
 7329                    buffer.edit(edits.iter().cloned(), None, cx)
 7330                });
 7331
 7332                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7333                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7334                });
 7335
 7336                let selections = self.selections.disjoint_anchors();
 7337                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7338                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7339                    if has_new_transaction {
 7340                        self.selection_history
 7341                            .insert_transaction(transaction_id_now, selections);
 7342                    }
 7343                }
 7344
 7345                self.update_visible_inline_completion(window, cx);
 7346                if self.active_inline_completion.is_none() {
 7347                    self.refresh_inline_completion(true, true, window, cx);
 7348                }
 7349
 7350                cx.notify();
 7351            }
 7352        }
 7353
 7354        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7355    }
 7356
 7357    pub fn accept_partial_inline_completion(
 7358        &mut self,
 7359        _: &AcceptPartialEditPrediction,
 7360        window: &mut Window,
 7361        cx: &mut Context<Self>,
 7362    ) {
 7363        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7364            return;
 7365        };
 7366        if self.selections.count() != 1 {
 7367            return;
 7368        }
 7369
 7370        self.report_inline_completion_event(
 7371            active_inline_completion.completion_id.clone(),
 7372            true,
 7373            cx,
 7374        );
 7375
 7376        match &active_inline_completion.completion {
 7377            InlineCompletion::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            InlineCompletion::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_inline_completion(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_inline_completion(
 7432        &mut self,
 7433        should_report_inline_completion_event: bool,
 7434        cx: &mut Context<Self>,
 7435    ) -> bool {
 7436        if should_report_inline_completion_event {
 7437            let completion_id = self
 7438                .active_inline_completion
 7439                .as_ref()
 7440                .and_then(|active_completion| active_completion.completion_id.clone());
 7441
 7442            self.report_inline_completion_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_inline_completion(cx)
 7450    }
 7451
 7452    fn report_inline_completion_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_inline_completion(&self) -> bool {
 7484        self.active_inline_completion.is_some()
 7485    }
 7486
 7487    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7488        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7489            return false;
 7490        };
 7491
 7492        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7493        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7494        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 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_inline_completion(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_inline_completion(window, cx);
 7663            cx.notify();
 7664        }
 7665    }
 7666
 7667    fn update_visible_inline_completion(
 7668        &mut self,
 7669        _window: &mut Window,
 7670        cx: &mut Context<Self>,
 7671    ) -> Option<()> {
 7672        let selection = self.selections.newest_anchor();
 7673        let cursor = selection.head();
 7674        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7675        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7676        let excerpt_id = cursor.excerpt_id;
 7677
 7678        let show_in_menu = self.show_edit_predictions_in_menu();
 7679        let completions_menu_has_precedence = !show_in_menu
 7680            && (self.context_menu.borrow().is_some()
 7681                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7682
 7683        if completions_menu_has_precedence
 7684            || !offset_selection.is_empty()
 7685            || self
 7686                .active_inline_completion
 7687                .as_ref()
 7688                .map_or(false, |completion| {
 7689                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7690                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7691                    !invalidation_range.contains(&offset_selection.head())
 7692                })
 7693        {
 7694            self.discard_inline_completion(false, cx);
 7695            return None;
 7696        }
 7697
 7698        self.take_active_inline_completion(cx);
 7699        let Some(provider) = self.edit_prediction_provider() else {
 7700            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7701            return None;
 7702        };
 7703
 7704        let (buffer, cursor_buffer_position) =
 7705            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7706
 7707        self.edit_prediction_settings =
 7708            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7709
 7710        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7711
 7712        if self.edit_prediction_indent_conflict {
 7713            let cursor_point = cursor.to_point(&multibuffer);
 7714
 7715            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7716
 7717            if let Some((_, indent)) = indents.iter().next() {
 7718                if indent.len == cursor_point.column {
 7719                    self.edit_prediction_indent_conflict = false;
 7720                }
 7721            }
 7722        }
 7723
 7724        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7725        let edits = inline_completion
 7726            .edits
 7727            .into_iter()
 7728            .flat_map(|(range, new_text)| {
 7729                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7730                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7731                Some((start..end, new_text))
 7732            })
 7733            .collect::<Vec<_>>();
 7734        if edits.is_empty() {
 7735            return None;
 7736        }
 7737
 7738        let first_edit_start = edits.first().unwrap().0.start;
 7739        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7740        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7741
 7742        let last_edit_end = edits.last().unwrap().0.end;
 7743        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7744        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7745
 7746        let cursor_row = cursor.to_point(&multibuffer).row;
 7747
 7748        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7749
 7750        let mut inlay_ids = Vec::new();
 7751        let invalidation_row_range;
 7752        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7753            Some(cursor_row..edit_end_row)
 7754        } else if cursor_row > edit_end_row {
 7755            Some(edit_start_row..cursor_row)
 7756        } else {
 7757            None
 7758        };
 7759        let is_move =
 7760            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7761        let completion = if is_move {
 7762            invalidation_row_range =
 7763                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7764            let target = first_edit_start;
 7765            InlineCompletion::Move { target, snapshot }
 7766        } else {
 7767            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7768                && !self.inline_completions_hidden_for_vim_mode;
 7769
 7770            if show_completions_in_buffer {
 7771                if edits
 7772                    .iter()
 7773                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7774                {
 7775                    let mut inlays = Vec::new();
 7776                    for (range, new_text) in &edits {
 7777                        let inlay = Inlay::inline_completion(
 7778                            post_inc(&mut self.next_inlay_id),
 7779                            range.start,
 7780                            new_text.as_str(),
 7781                        );
 7782                        inlay_ids.push(inlay.id);
 7783                        inlays.push(inlay);
 7784                    }
 7785
 7786                    self.splice_inlays(&[], inlays, cx);
 7787                } else {
 7788                    let background_color = cx.theme().status().deleted_background;
 7789                    self.highlight_text::<InlineCompletionHighlight>(
 7790                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7791                        HighlightStyle {
 7792                            background_color: Some(background_color),
 7793                            ..Default::default()
 7794                        },
 7795                        cx,
 7796                    );
 7797                }
 7798            }
 7799
 7800            invalidation_row_range = edit_start_row..edit_end_row;
 7801
 7802            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7803                if provider.show_tab_accept_marker() {
 7804                    EditDisplayMode::TabAccept
 7805                } else {
 7806                    EditDisplayMode::Inline
 7807                }
 7808            } else {
 7809                EditDisplayMode::DiffPopover
 7810            };
 7811
 7812            InlineCompletion::Edit {
 7813                edits,
 7814                edit_preview: inline_completion.edit_preview,
 7815                display_mode,
 7816                snapshot,
 7817            }
 7818        };
 7819
 7820        let invalidation_range = multibuffer
 7821            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7822            ..multibuffer.anchor_after(Point::new(
 7823                invalidation_row_range.end,
 7824                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7825            ));
 7826
 7827        self.stale_inline_completion_in_menu = None;
 7828        self.active_inline_completion = Some(InlineCompletionState {
 7829            inlay_ids,
 7830            completion,
 7831            completion_id: inline_completion.id,
 7832            invalidation_range,
 7833        });
 7834
 7835        cx.notify();
 7836
 7837        Some(())
 7838    }
 7839
 7840    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7841        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7842    }
 7843
 7844    fn clear_tasks(&mut self) {
 7845        self.tasks.clear()
 7846    }
 7847
 7848    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7849        if self.tasks.insert(key, value).is_some() {
 7850            // This case should hopefully be rare, but just in case...
 7851            log::error!(
 7852                "multiple different run targets found on a single line, only the last target will be rendered"
 7853            )
 7854        }
 7855    }
 7856
 7857    /// Get all display points of breakpoints that will be rendered within editor
 7858    ///
 7859    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7860    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7861    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7862    fn active_breakpoints(
 7863        &self,
 7864        range: Range<DisplayRow>,
 7865        window: &mut Window,
 7866        cx: &mut Context<Self>,
 7867    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7868        let mut breakpoint_display_points = HashMap::default();
 7869
 7870        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7871            return breakpoint_display_points;
 7872        };
 7873
 7874        let snapshot = self.snapshot(window, cx);
 7875
 7876        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7877        let Some(project) = self.project.as_ref() else {
 7878            return breakpoint_display_points;
 7879        };
 7880
 7881        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7882            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7883
 7884        for (buffer_snapshot, range, excerpt_id) in
 7885            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7886        {
 7887            let Some(buffer) = project
 7888                .read(cx)
 7889                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7890            else {
 7891                continue;
 7892            };
 7893            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7894                &buffer,
 7895                Some(
 7896                    buffer_snapshot.anchor_before(range.start)
 7897                        ..buffer_snapshot.anchor_after(range.end),
 7898                ),
 7899                buffer_snapshot,
 7900                cx,
 7901            );
 7902            for (breakpoint, state) in breakpoints {
 7903                let multi_buffer_anchor =
 7904                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7905                let position = multi_buffer_anchor
 7906                    .to_point(&multi_buffer_snapshot)
 7907                    .to_display_point(&snapshot);
 7908
 7909                breakpoint_display_points.insert(
 7910                    position.row(),
 7911                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7912                );
 7913            }
 7914        }
 7915
 7916        breakpoint_display_points
 7917    }
 7918
 7919    fn breakpoint_context_menu(
 7920        &self,
 7921        anchor: Anchor,
 7922        window: &mut Window,
 7923        cx: &mut Context<Self>,
 7924    ) -> Entity<ui::ContextMenu> {
 7925        let weak_editor = cx.weak_entity();
 7926        let focus_handle = self.focus_handle(cx);
 7927
 7928        let row = self
 7929            .buffer
 7930            .read(cx)
 7931            .snapshot(cx)
 7932            .summary_for_anchor::<Point>(&anchor)
 7933            .row;
 7934
 7935        let breakpoint = self
 7936            .breakpoint_at_row(row, window, cx)
 7937            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7938
 7939        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7940            "Edit Log Breakpoint"
 7941        } else {
 7942            "Set Log Breakpoint"
 7943        };
 7944
 7945        let condition_breakpoint_msg = if breakpoint
 7946            .as_ref()
 7947            .is_some_and(|bp| bp.1.condition.is_some())
 7948        {
 7949            "Edit Condition Breakpoint"
 7950        } else {
 7951            "Set Condition Breakpoint"
 7952        };
 7953
 7954        let hit_condition_breakpoint_msg = if breakpoint
 7955            .as_ref()
 7956            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7957        {
 7958            "Edit Hit Condition Breakpoint"
 7959        } else {
 7960            "Set Hit Condition Breakpoint"
 7961        };
 7962
 7963        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7964            "Unset Breakpoint"
 7965        } else {
 7966            "Set Breakpoint"
 7967        };
 7968
 7969        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7970
 7971        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7972            BreakpointState::Enabled => Some("Disable"),
 7973            BreakpointState::Disabled => Some("Enable"),
 7974        });
 7975
 7976        let (anchor, breakpoint) =
 7977            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7978
 7979        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7980            menu.on_blur_subscription(Subscription::new(|| {}))
 7981                .context(focus_handle)
 7982                .when(run_to_cursor, |this| {
 7983                    let weak_editor = weak_editor.clone();
 7984                    this.entry("Run to cursor", None, move |window, cx| {
 7985                        weak_editor
 7986                            .update(cx, |editor, cx| {
 7987                                editor.change_selections(
 7988                                    SelectionEffects::no_scroll(),
 7989                                    window,
 7990                                    cx,
 7991                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 7992                                );
 7993                            })
 7994                            .ok();
 7995
 7996                        window.dispatch_action(Box::new(RunToCursor), cx);
 7997                    })
 7998                    .separator()
 7999                })
 8000                .when_some(toggle_state_msg, |this, msg| {
 8001                    this.entry(msg, None, {
 8002                        let weak_editor = weak_editor.clone();
 8003                        let breakpoint = breakpoint.clone();
 8004                        move |_window, cx| {
 8005                            weak_editor
 8006                                .update(cx, |this, cx| {
 8007                                    this.edit_breakpoint_at_anchor(
 8008                                        anchor,
 8009                                        breakpoint.as_ref().clone(),
 8010                                        BreakpointEditAction::InvertState,
 8011                                        cx,
 8012                                    );
 8013                                })
 8014                                .log_err();
 8015                        }
 8016                    })
 8017                })
 8018                .entry(set_breakpoint_msg, None, {
 8019                    let weak_editor = weak_editor.clone();
 8020                    let breakpoint = breakpoint.clone();
 8021                    move |_window, cx| {
 8022                        weak_editor
 8023                            .update(cx, |this, cx| {
 8024                                this.edit_breakpoint_at_anchor(
 8025                                    anchor,
 8026                                    breakpoint.as_ref().clone(),
 8027                                    BreakpointEditAction::Toggle,
 8028                                    cx,
 8029                                );
 8030                            })
 8031                            .log_err();
 8032                    }
 8033                })
 8034                .entry(log_breakpoint_msg, None, {
 8035                    let breakpoint = breakpoint.clone();
 8036                    let weak_editor = weak_editor.clone();
 8037                    move |window, cx| {
 8038                        weak_editor
 8039                            .update(cx, |this, cx| {
 8040                                this.add_edit_breakpoint_block(
 8041                                    anchor,
 8042                                    breakpoint.as_ref(),
 8043                                    BreakpointPromptEditAction::Log,
 8044                                    window,
 8045                                    cx,
 8046                                );
 8047                            })
 8048                            .log_err();
 8049                    }
 8050                })
 8051                .entry(condition_breakpoint_msg, None, {
 8052                    let breakpoint = breakpoint.clone();
 8053                    let weak_editor = weak_editor.clone();
 8054                    move |window, cx| {
 8055                        weak_editor
 8056                            .update(cx, |this, cx| {
 8057                                this.add_edit_breakpoint_block(
 8058                                    anchor,
 8059                                    breakpoint.as_ref(),
 8060                                    BreakpointPromptEditAction::Condition,
 8061                                    window,
 8062                                    cx,
 8063                                );
 8064                            })
 8065                            .log_err();
 8066                    }
 8067                })
 8068                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8069                    weak_editor
 8070                        .update(cx, |this, cx| {
 8071                            this.add_edit_breakpoint_block(
 8072                                anchor,
 8073                                breakpoint.as_ref(),
 8074                                BreakpointPromptEditAction::HitCondition,
 8075                                window,
 8076                                cx,
 8077                            );
 8078                        })
 8079                        .log_err();
 8080                })
 8081        })
 8082    }
 8083
 8084    fn render_breakpoint(
 8085        &self,
 8086        position: Anchor,
 8087        row: DisplayRow,
 8088        breakpoint: &Breakpoint,
 8089        state: Option<BreakpointSessionState>,
 8090        cx: &mut Context<Self>,
 8091    ) -> IconButton {
 8092        let is_rejected = state.is_some_and(|s| !s.verified);
 8093        // Is it a breakpoint that shows up when hovering over gutter?
 8094        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8095            (false, false),
 8096            |PhantomBreakpointIndicator {
 8097                 is_active,
 8098                 display_row,
 8099                 collides_with_existing_breakpoint,
 8100             }| {
 8101                (
 8102                    is_active && display_row == row,
 8103                    collides_with_existing_breakpoint,
 8104                )
 8105            },
 8106        );
 8107
 8108        let (color, icon) = {
 8109            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8110                (false, false) => ui::IconName::DebugBreakpoint,
 8111                (true, false) => ui::IconName::DebugLogBreakpoint,
 8112                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8113                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8114            };
 8115
 8116            let color = if is_phantom {
 8117                Color::Hint
 8118            } else if is_rejected {
 8119                Color::Disabled
 8120            } else {
 8121                Color::Debugger
 8122            };
 8123
 8124            (color, icon)
 8125        };
 8126
 8127        let breakpoint = Arc::from(breakpoint.clone());
 8128
 8129        let alt_as_text = gpui::Keystroke {
 8130            modifiers: Modifiers::secondary_key(),
 8131            ..Default::default()
 8132        };
 8133        let primary_action_text = if breakpoint.is_disabled() {
 8134            "Enable breakpoint"
 8135        } else if is_phantom && !collides_with_existing {
 8136            "Set breakpoint"
 8137        } else {
 8138            "Unset breakpoint"
 8139        };
 8140        let focus_handle = self.focus_handle.clone();
 8141
 8142        let meta = if is_rejected {
 8143            SharedString::from("No executable code is associated with this line.")
 8144        } else if collides_with_existing && !breakpoint.is_disabled() {
 8145            SharedString::from(format!(
 8146                "{alt_as_text}-click to disable,\nright-click for more options."
 8147            ))
 8148        } else {
 8149            SharedString::from("Right-click for more options.")
 8150        };
 8151        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8152            .icon_size(IconSize::XSmall)
 8153            .size(ui::ButtonSize::None)
 8154            .when(is_rejected, |this| {
 8155                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8156            })
 8157            .icon_color(color)
 8158            .style(ButtonStyle::Transparent)
 8159            .on_click(cx.listener({
 8160                let breakpoint = breakpoint.clone();
 8161
 8162                move |editor, event: &ClickEvent, window, cx| {
 8163                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8164                        BreakpointEditAction::InvertState
 8165                    } else {
 8166                        BreakpointEditAction::Toggle
 8167                    };
 8168
 8169                    window.focus(&editor.focus_handle(cx));
 8170                    editor.edit_breakpoint_at_anchor(
 8171                        position,
 8172                        breakpoint.as_ref().clone(),
 8173                        edit_action,
 8174                        cx,
 8175                    );
 8176                }
 8177            }))
 8178            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8179                editor.set_breakpoint_context_menu(
 8180                    row,
 8181                    Some(position),
 8182                    event.down.position,
 8183                    window,
 8184                    cx,
 8185                );
 8186            }))
 8187            .tooltip(move |window, cx| {
 8188                Tooltip::with_meta_in(
 8189                    primary_action_text,
 8190                    Some(&ToggleBreakpoint),
 8191                    meta.clone(),
 8192                    &focus_handle,
 8193                    window,
 8194                    cx,
 8195                )
 8196            })
 8197    }
 8198
 8199    fn build_tasks_context(
 8200        project: &Entity<Project>,
 8201        buffer: &Entity<Buffer>,
 8202        buffer_row: u32,
 8203        tasks: &Arc<RunnableTasks>,
 8204        cx: &mut Context<Self>,
 8205    ) -> Task<Option<task::TaskContext>> {
 8206        let position = Point::new(buffer_row, tasks.column);
 8207        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8208        let location = Location {
 8209            buffer: buffer.clone(),
 8210            range: range_start..range_start,
 8211        };
 8212        // Fill in the environmental variables from the tree-sitter captures
 8213        let mut captured_task_variables = TaskVariables::default();
 8214        for (capture_name, value) in tasks.extra_variables.clone() {
 8215            captured_task_variables.insert(
 8216                task::VariableName::Custom(capture_name.into()),
 8217                value.clone(),
 8218            );
 8219        }
 8220        project.update(cx, |project, cx| {
 8221            project.task_store().update(cx, |task_store, cx| {
 8222                task_store.task_context_for_location(captured_task_variables, location, cx)
 8223            })
 8224        })
 8225    }
 8226
 8227    pub fn spawn_nearest_task(
 8228        &mut self,
 8229        action: &SpawnNearestTask,
 8230        window: &mut Window,
 8231        cx: &mut Context<Self>,
 8232    ) {
 8233        let Some((workspace, _)) = self.workspace.clone() else {
 8234            return;
 8235        };
 8236        let Some(project) = self.project.clone() else {
 8237            return;
 8238        };
 8239
 8240        // Try to find a closest, enclosing node using tree-sitter that has a task
 8241        let Some((buffer, buffer_row, tasks)) = self
 8242            .find_enclosing_node_task(cx)
 8243            // Or find the task that's closest in row-distance.
 8244            .or_else(|| self.find_closest_task(cx))
 8245        else {
 8246            return;
 8247        };
 8248
 8249        let reveal_strategy = action.reveal;
 8250        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8251        cx.spawn_in(window, async move |_, cx| {
 8252            let context = task_context.await?;
 8253            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8254
 8255            let resolved = &mut resolved_task.resolved;
 8256            resolved.reveal = reveal_strategy;
 8257
 8258            workspace
 8259                .update_in(cx, |workspace, window, cx| {
 8260                    workspace.schedule_resolved_task(
 8261                        task_source_kind,
 8262                        resolved_task,
 8263                        false,
 8264                        window,
 8265                        cx,
 8266                    );
 8267                })
 8268                .ok()
 8269        })
 8270        .detach();
 8271    }
 8272
 8273    fn find_closest_task(
 8274        &mut self,
 8275        cx: &mut Context<Self>,
 8276    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8277        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8278
 8279        let ((buffer_id, row), tasks) = self
 8280            .tasks
 8281            .iter()
 8282            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8283
 8284        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8285        let tasks = Arc::new(tasks.to_owned());
 8286        Some((buffer, *row, tasks))
 8287    }
 8288
 8289    fn find_enclosing_node_task(
 8290        &mut self,
 8291        cx: &mut Context<Self>,
 8292    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8293        let snapshot = self.buffer.read(cx).snapshot(cx);
 8294        let offset = self.selections.newest::<usize>(cx).head();
 8295        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8296        let buffer_id = excerpt.buffer().remote_id();
 8297
 8298        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8299        let mut cursor = layer.node().walk();
 8300
 8301        while cursor.goto_first_child_for_byte(offset).is_some() {
 8302            if cursor.node().end_byte() == offset {
 8303                cursor.goto_next_sibling();
 8304            }
 8305        }
 8306
 8307        // Ascend to the smallest ancestor that contains the range and has a task.
 8308        loop {
 8309            let node = cursor.node();
 8310            let node_range = node.byte_range();
 8311            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8312
 8313            // Check if this node contains our offset
 8314            if node_range.start <= offset && node_range.end >= offset {
 8315                // If it contains offset, check for task
 8316                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8317                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8318                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8319                }
 8320            }
 8321
 8322            if !cursor.goto_parent() {
 8323                break;
 8324            }
 8325        }
 8326        None
 8327    }
 8328
 8329    fn render_run_indicator(
 8330        &self,
 8331        _style: &EditorStyle,
 8332        is_active: bool,
 8333        row: DisplayRow,
 8334        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8335        cx: &mut Context<Self>,
 8336    ) -> IconButton {
 8337        let color = Color::Muted;
 8338        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8339
 8340        IconButton::new(
 8341            ("run_indicator", row.0 as usize),
 8342            ui::IconName::PlayOutlined,
 8343        )
 8344        .shape(ui::IconButtonShape::Square)
 8345        .icon_size(IconSize::XSmall)
 8346        .icon_color(color)
 8347        .toggle_state(is_active)
 8348        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8349            let quick_launch = e.down.button == MouseButton::Left;
 8350            window.focus(&editor.focus_handle(cx));
 8351            editor.toggle_code_actions(
 8352                &ToggleCodeActions {
 8353                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8354                    quick_launch,
 8355                },
 8356                window,
 8357                cx,
 8358            );
 8359        }))
 8360        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8361            editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 8362        }))
 8363    }
 8364
 8365    pub fn context_menu_visible(&self) -> bool {
 8366        !self.edit_prediction_preview_is_active()
 8367            && self
 8368                .context_menu
 8369                .borrow()
 8370                .as_ref()
 8371                .map_or(false, |menu| menu.visible())
 8372    }
 8373
 8374    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8375        self.context_menu
 8376            .borrow()
 8377            .as_ref()
 8378            .map(|menu| menu.origin())
 8379    }
 8380
 8381    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8382        self.context_menu_options = Some(options);
 8383    }
 8384
 8385    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8386    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8387
 8388    fn render_edit_prediction_popover(
 8389        &mut self,
 8390        text_bounds: &Bounds<Pixels>,
 8391        content_origin: gpui::Point<Pixels>,
 8392        right_margin: Pixels,
 8393        editor_snapshot: &EditorSnapshot,
 8394        visible_row_range: Range<DisplayRow>,
 8395        scroll_top: f32,
 8396        scroll_bottom: f32,
 8397        line_layouts: &[LineWithInvisibles],
 8398        line_height: Pixels,
 8399        scroll_pixel_position: gpui::Point<Pixels>,
 8400        newest_selection_head: Option<DisplayPoint>,
 8401        editor_width: Pixels,
 8402        style: &EditorStyle,
 8403        window: &mut Window,
 8404        cx: &mut App,
 8405    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8406        if self.mode().is_minimap() {
 8407            return None;
 8408        }
 8409        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8410
 8411        if self.edit_prediction_visible_in_cursor_popover(true) {
 8412            return None;
 8413        }
 8414
 8415        match &active_inline_completion.completion {
 8416            InlineCompletion::Move { target, .. } => {
 8417                let target_display_point = target.to_display_point(editor_snapshot);
 8418
 8419                if self.edit_prediction_requires_modifier() {
 8420                    if !self.edit_prediction_preview_is_active() {
 8421                        return None;
 8422                    }
 8423
 8424                    self.render_edit_prediction_modifier_jump_popover(
 8425                        text_bounds,
 8426                        content_origin,
 8427                        visible_row_range,
 8428                        line_layouts,
 8429                        line_height,
 8430                        scroll_pixel_position,
 8431                        newest_selection_head,
 8432                        target_display_point,
 8433                        window,
 8434                        cx,
 8435                    )
 8436                } else {
 8437                    self.render_edit_prediction_eager_jump_popover(
 8438                        text_bounds,
 8439                        content_origin,
 8440                        editor_snapshot,
 8441                        visible_row_range,
 8442                        scroll_top,
 8443                        scroll_bottom,
 8444                        line_height,
 8445                        scroll_pixel_position,
 8446                        target_display_point,
 8447                        editor_width,
 8448                        window,
 8449                        cx,
 8450                    )
 8451                }
 8452            }
 8453            InlineCompletion::Edit {
 8454                display_mode: EditDisplayMode::Inline,
 8455                ..
 8456            } => None,
 8457            InlineCompletion::Edit {
 8458                display_mode: EditDisplayMode::TabAccept,
 8459                edits,
 8460                ..
 8461            } => {
 8462                let range = &edits.first()?.0;
 8463                let target_display_point = range.end.to_display_point(editor_snapshot);
 8464
 8465                self.render_edit_prediction_end_of_line_popover(
 8466                    "Accept",
 8467                    editor_snapshot,
 8468                    visible_row_range,
 8469                    target_display_point,
 8470                    line_height,
 8471                    scroll_pixel_position,
 8472                    content_origin,
 8473                    editor_width,
 8474                    window,
 8475                    cx,
 8476                )
 8477            }
 8478            InlineCompletion::Edit {
 8479                edits,
 8480                edit_preview,
 8481                display_mode: EditDisplayMode::DiffPopover,
 8482                snapshot,
 8483            } => self.render_edit_prediction_diff_popover(
 8484                text_bounds,
 8485                content_origin,
 8486                right_margin,
 8487                editor_snapshot,
 8488                visible_row_range,
 8489                line_layouts,
 8490                line_height,
 8491                scroll_pixel_position,
 8492                newest_selection_head,
 8493                editor_width,
 8494                style,
 8495                edits,
 8496                edit_preview,
 8497                snapshot,
 8498                window,
 8499                cx,
 8500            ),
 8501        }
 8502    }
 8503
 8504    fn render_edit_prediction_modifier_jump_popover(
 8505        &mut self,
 8506        text_bounds: &Bounds<Pixels>,
 8507        content_origin: gpui::Point<Pixels>,
 8508        visible_row_range: Range<DisplayRow>,
 8509        line_layouts: &[LineWithInvisibles],
 8510        line_height: Pixels,
 8511        scroll_pixel_position: gpui::Point<Pixels>,
 8512        newest_selection_head: Option<DisplayPoint>,
 8513        target_display_point: DisplayPoint,
 8514        window: &mut Window,
 8515        cx: &mut App,
 8516    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8517        let scrolled_content_origin =
 8518            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8519
 8520        const SCROLL_PADDING_Y: Pixels = px(12.);
 8521
 8522        if target_display_point.row() < visible_row_range.start {
 8523            return self.render_edit_prediction_scroll_popover(
 8524                |_| SCROLL_PADDING_Y,
 8525                IconName::ArrowUp,
 8526                visible_row_range,
 8527                line_layouts,
 8528                newest_selection_head,
 8529                scrolled_content_origin,
 8530                window,
 8531                cx,
 8532            );
 8533        } else if target_display_point.row() >= visible_row_range.end {
 8534            return self.render_edit_prediction_scroll_popover(
 8535                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8536                IconName::ArrowDown,
 8537                visible_row_range,
 8538                line_layouts,
 8539                newest_selection_head,
 8540                scrolled_content_origin,
 8541                window,
 8542                cx,
 8543            );
 8544        }
 8545
 8546        const POLE_WIDTH: Pixels = px(2.);
 8547
 8548        let line_layout =
 8549            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8550        let target_column = target_display_point.column() as usize;
 8551
 8552        let target_x = line_layout.x_for_index(target_column);
 8553        let target_y =
 8554            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8555
 8556        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8557
 8558        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8559        border_color.l += 0.001;
 8560
 8561        let mut element = v_flex()
 8562            .items_end()
 8563            .when(flag_on_right, |el| el.items_start())
 8564            .child(if flag_on_right {
 8565                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8566                    .rounded_bl(px(0.))
 8567                    .rounded_tl(px(0.))
 8568                    .border_l_2()
 8569                    .border_color(border_color)
 8570            } else {
 8571                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8572                    .rounded_br(px(0.))
 8573                    .rounded_tr(px(0.))
 8574                    .border_r_2()
 8575                    .border_color(border_color)
 8576            })
 8577            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8578            .into_any();
 8579
 8580        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8581
 8582        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8583            - point(
 8584                if flag_on_right {
 8585                    POLE_WIDTH
 8586                } else {
 8587                    size.width - POLE_WIDTH
 8588                },
 8589                size.height - line_height,
 8590            );
 8591
 8592        origin.x = origin.x.max(content_origin.x);
 8593
 8594        element.prepaint_at(origin, window, cx);
 8595
 8596        Some((element, origin))
 8597    }
 8598
 8599    fn render_edit_prediction_scroll_popover(
 8600        &mut self,
 8601        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8602        scroll_icon: IconName,
 8603        visible_row_range: Range<DisplayRow>,
 8604        line_layouts: &[LineWithInvisibles],
 8605        newest_selection_head: Option<DisplayPoint>,
 8606        scrolled_content_origin: gpui::Point<Pixels>,
 8607        window: &mut Window,
 8608        cx: &mut App,
 8609    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8610        let mut element = self
 8611            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8612            .into_any();
 8613
 8614        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8615
 8616        let cursor = newest_selection_head?;
 8617        let cursor_row_layout =
 8618            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8619        let cursor_column = cursor.column() as usize;
 8620
 8621        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8622
 8623        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8624
 8625        element.prepaint_at(origin, window, cx);
 8626        Some((element, origin))
 8627    }
 8628
 8629    fn render_edit_prediction_eager_jump_popover(
 8630        &mut self,
 8631        text_bounds: &Bounds<Pixels>,
 8632        content_origin: gpui::Point<Pixels>,
 8633        editor_snapshot: &EditorSnapshot,
 8634        visible_row_range: Range<DisplayRow>,
 8635        scroll_top: f32,
 8636        scroll_bottom: f32,
 8637        line_height: Pixels,
 8638        scroll_pixel_position: gpui::Point<Pixels>,
 8639        target_display_point: DisplayPoint,
 8640        editor_width: Pixels,
 8641        window: &mut Window,
 8642        cx: &mut App,
 8643    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8644        if target_display_point.row().as_f32() < scroll_top {
 8645            let mut element = self
 8646                .render_edit_prediction_line_popover(
 8647                    "Jump to Edit",
 8648                    Some(IconName::ArrowUp),
 8649                    window,
 8650                    cx,
 8651                )?
 8652                .into_any();
 8653
 8654            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8655            let offset = point(
 8656                (text_bounds.size.width - size.width) / 2.,
 8657                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8658            );
 8659
 8660            let origin = text_bounds.origin + offset;
 8661            element.prepaint_at(origin, window, cx);
 8662            Some((element, origin))
 8663        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8664            let mut element = self
 8665                .render_edit_prediction_line_popover(
 8666                    "Jump to Edit",
 8667                    Some(IconName::ArrowDown),
 8668                    window,
 8669                    cx,
 8670                )?
 8671                .into_any();
 8672
 8673            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8674            let offset = point(
 8675                (text_bounds.size.width - size.width) / 2.,
 8676                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8677            );
 8678
 8679            let origin = text_bounds.origin + offset;
 8680            element.prepaint_at(origin, window, cx);
 8681            Some((element, origin))
 8682        } else {
 8683            self.render_edit_prediction_end_of_line_popover(
 8684                "Jump to Edit",
 8685                editor_snapshot,
 8686                visible_row_range,
 8687                target_display_point,
 8688                line_height,
 8689                scroll_pixel_position,
 8690                content_origin,
 8691                editor_width,
 8692                window,
 8693                cx,
 8694            )
 8695        }
 8696    }
 8697
 8698    fn render_edit_prediction_end_of_line_popover(
 8699        self: &mut Editor,
 8700        label: &'static str,
 8701        editor_snapshot: &EditorSnapshot,
 8702        visible_row_range: Range<DisplayRow>,
 8703        target_display_point: DisplayPoint,
 8704        line_height: Pixels,
 8705        scroll_pixel_position: gpui::Point<Pixels>,
 8706        content_origin: gpui::Point<Pixels>,
 8707        editor_width: Pixels,
 8708        window: &mut Window,
 8709        cx: &mut App,
 8710    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8711        let target_line_end = DisplayPoint::new(
 8712            target_display_point.row(),
 8713            editor_snapshot.line_len(target_display_point.row()),
 8714        );
 8715
 8716        let mut element = self
 8717            .render_edit_prediction_line_popover(label, None, window, cx)?
 8718            .into_any();
 8719
 8720        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8721
 8722        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8723
 8724        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8725        let mut origin = start_point
 8726            + line_origin
 8727            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8728        origin.x = origin.x.max(content_origin.x);
 8729
 8730        let max_x = content_origin.x + editor_width - size.width;
 8731
 8732        if origin.x > max_x {
 8733            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8734
 8735            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8736                origin.y += offset;
 8737                IconName::ArrowUp
 8738            } else {
 8739                origin.y -= offset;
 8740                IconName::ArrowDown
 8741            };
 8742
 8743            element = self
 8744                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8745                .into_any();
 8746
 8747            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8748
 8749            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8750        }
 8751
 8752        element.prepaint_at(origin, window, cx);
 8753        Some((element, origin))
 8754    }
 8755
 8756    fn render_edit_prediction_diff_popover(
 8757        self: &Editor,
 8758        text_bounds: &Bounds<Pixels>,
 8759        content_origin: gpui::Point<Pixels>,
 8760        right_margin: Pixels,
 8761        editor_snapshot: &EditorSnapshot,
 8762        visible_row_range: Range<DisplayRow>,
 8763        line_layouts: &[LineWithInvisibles],
 8764        line_height: Pixels,
 8765        scroll_pixel_position: gpui::Point<Pixels>,
 8766        newest_selection_head: Option<DisplayPoint>,
 8767        editor_width: Pixels,
 8768        style: &EditorStyle,
 8769        edits: &Vec<(Range<Anchor>, String)>,
 8770        edit_preview: &Option<language::EditPreview>,
 8771        snapshot: &language::BufferSnapshot,
 8772        window: &mut Window,
 8773        cx: &mut App,
 8774    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8775        let edit_start = edits
 8776            .first()
 8777            .unwrap()
 8778            .0
 8779            .start
 8780            .to_display_point(editor_snapshot);
 8781        let edit_end = edits
 8782            .last()
 8783            .unwrap()
 8784            .0
 8785            .end
 8786            .to_display_point(editor_snapshot);
 8787
 8788        let is_visible = visible_row_range.contains(&edit_start.row())
 8789            || visible_row_range.contains(&edit_end.row());
 8790        if !is_visible {
 8791            return None;
 8792        }
 8793
 8794        let highlighted_edits =
 8795            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8796
 8797        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8798        let line_count = highlighted_edits.text.lines().count();
 8799
 8800        const BORDER_WIDTH: Pixels = px(1.);
 8801
 8802        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8803        let has_keybind = keybind.is_some();
 8804
 8805        let mut element = h_flex()
 8806            .items_start()
 8807            .child(
 8808                h_flex()
 8809                    .bg(cx.theme().colors().editor_background)
 8810                    .border(BORDER_WIDTH)
 8811                    .shadow_xs()
 8812                    .border_color(cx.theme().colors().border)
 8813                    .rounded_l_lg()
 8814                    .when(line_count > 1, |el| el.rounded_br_lg())
 8815                    .pr_1()
 8816                    .child(styled_text),
 8817            )
 8818            .child(
 8819                h_flex()
 8820                    .h(line_height + BORDER_WIDTH * 2.)
 8821                    .px_1p5()
 8822                    .gap_1()
 8823                    // Workaround: For some reason, there's a gap if we don't do this
 8824                    .ml(-BORDER_WIDTH)
 8825                    .shadow(vec![gpui::BoxShadow {
 8826                        color: gpui::black().opacity(0.05),
 8827                        offset: point(px(1.), px(1.)),
 8828                        blur_radius: px(2.),
 8829                        spread_radius: px(0.),
 8830                    }])
 8831                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8832                    .border(BORDER_WIDTH)
 8833                    .border_color(cx.theme().colors().border)
 8834                    .rounded_r_lg()
 8835                    .id("edit_prediction_diff_popover_keybind")
 8836                    .when(!has_keybind, |el| {
 8837                        let status_colors = cx.theme().status();
 8838
 8839                        el.bg(status_colors.error_background)
 8840                            .border_color(status_colors.error.opacity(0.6))
 8841                            .child(Icon::new(IconName::Info).color(Color::Error))
 8842                            .cursor_default()
 8843                            .hoverable_tooltip(move |_window, cx| {
 8844                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8845                            })
 8846                    })
 8847                    .children(keybind),
 8848            )
 8849            .into_any();
 8850
 8851        let longest_row =
 8852            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8853        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8854            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8855        } else {
 8856            layout_line(
 8857                longest_row,
 8858                editor_snapshot,
 8859                style,
 8860                editor_width,
 8861                |_| false,
 8862                window,
 8863                cx,
 8864            )
 8865            .width
 8866        };
 8867
 8868        let viewport_bounds =
 8869            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8870                right: -right_margin,
 8871                ..Default::default()
 8872            });
 8873
 8874        let x_after_longest =
 8875            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8876                - scroll_pixel_position.x;
 8877
 8878        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8879
 8880        // Fully visible if it can be displayed within the window (allow overlapping other
 8881        // panes). However, this is only allowed if the popover starts within text_bounds.
 8882        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8883            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8884
 8885        let mut origin = if can_position_to_the_right {
 8886            point(
 8887                x_after_longest,
 8888                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8889                    - scroll_pixel_position.y,
 8890            )
 8891        } else {
 8892            let cursor_row = newest_selection_head.map(|head| head.row());
 8893            let above_edit = edit_start
 8894                .row()
 8895                .0
 8896                .checked_sub(line_count as u32)
 8897                .map(DisplayRow);
 8898            let below_edit = Some(edit_end.row() + 1);
 8899            let above_cursor =
 8900                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8901            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8902
 8903            // Place the edit popover adjacent to the edit if there is a location
 8904            // available that is onscreen and does not obscure the cursor. Otherwise,
 8905            // place it adjacent to the cursor.
 8906            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8907                .into_iter()
 8908                .flatten()
 8909                .find(|&start_row| {
 8910                    let end_row = start_row + line_count as u32;
 8911                    visible_row_range.contains(&start_row)
 8912                        && visible_row_range.contains(&end_row)
 8913                        && cursor_row.map_or(true, |cursor_row| {
 8914                            !((start_row..end_row).contains(&cursor_row))
 8915                        })
 8916                })?;
 8917
 8918            content_origin
 8919                + point(
 8920                    -scroll_pixel_position.x,
 8921                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8922                )
 8923        };
 8924
 8925        origin.x -= BORDER_WIDTH;
 8926
 8927        window.defer_draw(element, origin, 1);
 8928
 8929        // Do not return an element, since it will already be drawn due to defer_draw.
 8930        None
 8931    }
 8932
 8933    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8934        px(30.)
 8935    }
 8936
 8937    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8938        if self.read_only(cx) {
 8939            cx.theme().players().read_only()
 8940        } else {
 8941            self.style.as_ref().unwrap().local_player
 8942        }
 8943    }
 8944
 8945    fn render_edit_prediction_accept_keybind(
 8946        &self,
 8947        window: &mut Window,
 8948        cx: &App,
 8949    ) -> Option<AnyElement> {
 8950        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8951        let accept_keystroke = accept_binding.keystroke()?;
 8952
 8953        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8954
 8955        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8956            Color::Accent
 8957        } else {
 8958            Color::Muted
 8959        };
 8960
 8961        h_flex()
 8962            .px_0p5()
 8963            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8964            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8965            .text_size(TextSize::XSmall.rems(cx))
 8966            .child(h_flex().children(ui::render_modifiers(
 8967                &accept_keystroke.modifiers,
 8968                PlatformStyle::platform(),
 8969                Some(modifiers_color),
 8970                Some(IconSize::XSmall.rems().into()),
 8971                true,
 8972            )))
 8973            .when(is_platform_style_mac, |parent| {
 8974                parent.child(accept_keystroke.key.clone())
 8975            })
 8976            .when(!is_platform_style_mac, |parent| {
 8977                parent.child(
 8978                    Key::new(
 8979                        util::capitalize(&accept_keystroke.key),
 8980                        Some(Color::Default),
 8981                    )
 8982                    .size(Some(IconSize::XSmall.rems().into())),
 8983                )
 8984            })
 8985            .into_any()
 8986            .into()
 8987    }
 8988
 8989    fn render_edit_prediction_line_popover(
 8990        &self,
 8991        label: impl Into<SharedString>,
 8992        icon: Option<IconName>,
 8993        window: &mut Window,
 8994        cx: &App,
 8995    ) -> Option<Stateful<Div>> {
 8996        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8997
 8998        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8999        let has_keybind = keybind.is_some();
 9000
 9001        let result = h_flex()
 9002            .id("ep-line-popover")
 9003            .py_0p5()
 9004            .pl_1()
 9005            .pr(padding_right)
 9006            .gap_1()
 9007            .rounded_md()
 9008            .border_1()
 9009            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9010            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9011            .shadow_xs()
 9012            .when(!has_keybind, |el| {
 9013                let status_colors = cx.theme().status();
 9014
 9015                el.bg(status_colors.error_background)
 9016                    .border_color(status_colors.error.opacity(0.6))
 9017                    .pl_2()
 9018                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9019                    .cursor_default()
 9020                    .hoverable_tooltip(move |_window, cx| {
 9021                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9022                    })
 9023            })
 9024            .children(keybind)
 9025            .child(
 9026                Label::new(label)
 9027                    .size(LabelSize::Small)
 9028                    .when(!has_keybind, |el| {
 9029                        el.color(cx.theme().status().error.into()).strikethrough()
 9030                    }),
 9031            )
 9032            .when(!has_keybind, |el| {
 9033                el.child(
 9034                    h_flex().ml_1().child(
 9035                        Icon::new(IconName::Info)
 9036                            .size(IconSize::Small)
 9037                            .color(cx.theme().status().error.into()),
 9038                    ),
 9039                )
 9040            })
 9041            .when_some(icon, |element, icon| {
 9042                element.child(
 9043                    div()
 9044                        .mt(px(1.5))
 9045                        .child(Icon::new(icon).size(IconSize::Small)),
 9046                )
 9047            });
 9048
 9049        Some(result)
 9050    }
 9051
 9052    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9053        let accent_color = cx.theme().colors().text_accent;
 9054        let editor_bg_color = cx.theme().colors().editor_background;
 9055        editor_bg_color.blend(accent_color.opacity(0.1))
 9056    }
 9057
 9058    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9059        let accent_color = cx.theme().colors().text_accent;
 9060        let editor_bg_color = cx.theme().colors().editor_background;
 9061        editor_bg_color.blend(accent_color.opacity(0.6))
 9062    }
 9063
 9064    fn render_edit_prediction_cursor_popover(
 9065        &self,
 9066        min_width: Pixels,
 9067        max_width: Pixels,
 9068        cursor_point: Point,
 9069        style: &EditorStyle,
 9070        accept_keystroke: Option<&gpui::Keystroke>,
 9071        _window: &Window,
 9072        cx: &mut Context<Editor>,
 9073    ) -> Option<AnyElement> {
 9074        let provider = self.edit_prediction_provider.as_ref()?;
 9075
 9076        if provider.provider.needs_terms_acceptance(cx) {
 9077            return Some(
 9078                h_flex()
 9079                    .min_w(min_width)
 9080                    .flex_1()
 9081                    .px_2()
 9082                    .py_1()
 9083                    .gap_3()
 9084                    .elevation_2(cx)
 9085                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 9086                    .id("accept-terms")
 9087                    .cursor_pointer()
 9088                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 9089                    .on_click(cx.listener(|this, _event, window, cx| {
 9090                        cx.stop_propagation();
 9091                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 9092                        window.dispatch_action(
 9093                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 9094                            cx,
 9095                        );
 9096                    }))
 9097                    .child(
 9098                        h_flex()
 9099                            .flex_1()
 9100                            .gap_2()
 9101                            .child(Icon::new(IconName::ZedPredict))
 9102                            .child(Label::new("Accept Terms of Service"))
 9103                            .child(div().w_full())
 9104                            .child(
 9105                                Icon::new(IconName::ArrowUpRight)
 9106                                    .color(Color::Muted)
 9107                                    .size(IconSize::Small),
 9108                            )
 9109                            .into_any_element(),
 9110                    )
 9111                    .into_any(),
 9112            );
 9113        }
 9114
 9115        let is_refreshing = provider.provider.is_refreshing(cx);
 9116
 9117        fn pending_completion_container() -> Div {
 9118            h_flex()
 9119                .h_full()
 9120                .flex_1()
 9121                .gap_2()
 9122                .child(Icon::new(IconName::ZedPredict))
 9123        }
 9124
 9125        let completion = match &self.active_inline_completion {
 9126            Some(prediction) => {
 9127                if !self.has_visible_completions_menu() {
 9128                    const RADIUS: Pixels = px(6.);
 9129                    const BORDER_WIDTH: Pixels = px(1.);
 9130
 9131                    return Some(
 9132                        h_flex()
 9133                            .elevation_2(cx)
 9134                            .border(BORDER_WIDTH)
 9135                            .border_color(cx.theme().colors().border)
 9136                            .when(accept_keystroke.is_none(), |el| {
 9137                                el.border_color(cx.theme().status().error)
 9138                            })
 9139                            .rounded(RADIUS)
 9140                            .rounded_tl(px(0.))
 9141                            .overflow_hidden()
 9142                            .child(div().px_1p5().child(match &prediction.completion {
 9143                                InlineCompletion::Move { target, snapshot } => {
 9144                                    use text::ToPoint as _;
 9145                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 9146                                    {
 9147                                        Icon::new(IconName::ZedPredictDown)
 9148                                    } else {
 9149                                        Icon::new(IconName::ZedPredictUp)
 9150                                    }
 9151                                }
 9152                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 9153                            }))
 9154                            .child(
 9155                                h_flex()
 9156                                    .gap_1()
 9157                                    .py_1()
 9158                                    .px_2()
 9159                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9160                                    .border_l_1()
 9161                                    .border_color(cx.theme().colors().border)
 9162                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9163                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9164                                        el.child(
 9165                                            Label::new("Hold")
 9166                                                .size(LabelSize::Small)
 9167                                                .when(accept_keystroke.is_none(), |el| {
 9168                                                    el.strikethrough()
 9169                                                })
 9170                                                .line_height_style(LineHeightStyle::UiLabel),
 9171                                        )
 9172                                    })
 9173                                    .id("edit_prediction_cursor_popover_keybind")
 9174                                    .when(accept_keystroke.is_none(), |el| {
 9175                                        let status_colors = cx.theme().status();
 9176
 9177                                        el.bg(status_colors.error_background)
 9178                                            .border_color(status_colors.error.opacity(0.6))
 9179                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9180                                            .cursor_default()
 9181                                            .hoverable_tooltip(move |_window, cx| {
 9182                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9183                                                    .into()
 9184                                            })
 9185                                    })
 9186                                    .when_some(
 9187                                        accept_keystroke.as_ref(),
 9188                                        |el, accept_keystroke| {
 9189                                            el.child(h_flex().children(ui::render_modifiers(
 9190                                                &accept_keystroke.modifiers,
 9191                                                PlatformStyle::platform(),
 9192                                                Some(Color::Default),
 9193                                                Some(IconSize::XSmall.rems().into()),
 9194                                                false,
 9195                                            )))
 9196                                        },
 9197                                    ),
 9198                            )
 9199                            .into_any(),
 9200                    );
 9201                }
 9202
 9203                self.render_edit_prediction_cursor_popover_preview(
 9204                    prediction,
 9205                    cursor_point,
 9206                    style,
 9207                    cx,
 9208                )?
 9209            }
 9210
 9211            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 9212                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9213                    stale_completion,
 9214                    cursor_point,
 9215                    style,
 9216                    cx,
 9217                )?,
 9218
 9219                None => {
 9220                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 9221                }
 9222            },
 9223
 9224            None => pending_completion_container().child(Label::new("No Prediction")),
 9225        };
 9226
 9227        let completion = if is_refreshing {
 9228            completion
 9229                .with_animation(
 9230                    "loading-completion",
 9231                    Animation::new(Duration::from_secs(2))
 9232                        .repeat()
 9233                        .with_easing(pulsating_between(0.4, 0.8)),
 9234                    |label, delta| label.opacity(delta),
 9235                )
 9236                .into_any_element()
 9237        } else {
 9238            completion.into_any_element()
 9239        };
 9240
 9241        let has_completion = self.active_inline_completion.is_some();
 9242
 9243        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9244        Some(
 9245            h_flex()
 9246                .min_w(min_width)
 9247                .max_w(max_width)
 9248                .flex_1()
 9249                .elevation_2(cx)
 9250                .border_color(cx.theme().colors().border)
 9251                .child(
 9252                    div()
 9253                        .flex_1()
 9254                        .py_1()
 9255                        .px_2()
 9256                        .overflow_hidden()
 9257                        .child(completion),
 9258                )
 9259                .when_some(accept_keystroke, |el, accept_keystroke| {
 9260                    if !accept_keystroke.modifiers.modified() {
 9261                        return el;
 9262                    }
 9263
 9264                    el.child(
 9265                        h_flex()
 9266                            .h_full()
 9267                            .border_l_1()
 9268                            .rounded_r_lg()
 9269                            .border_color(cx.theme().colors().border)
 9270                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9271                            .gap_1()
 9272                            .py_1()
 9273                            .px_2()
 9274                            .child(
 9275                                h_flex()
 9276                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9277                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9278                                    .child(h_flex().children(ui::render_modifiers(
 9279                                        &accept_keystroke.modifiers,
 9280                                        PlatformStyle::platform(),
 9281                                        Some(if !has_completion {
 9282                                            Color::Muted
 9283                                        } else {
 9284                                            Color::Default
 9285                                        }),
 9286                                        None,
 9287                                        false,
 9288                                    ))),
 9289                            )
 9290                            .child(Label::new("Preview").into_any_element())
 9291                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9292                    )
 9293                })
 9294                .into_any(),
 9295        )
 9296    }
 9297
 9298    fn render_edit_prediction_cursor_popover_preview(
 9299        &self,
 9300        completion: &InlineCompletionState,
 9301        cursor_point: Point,
 9302        style: &EditorStyle,
 9303        cx: &mut Context<Editor>,
 9304    ) -> Option<Div> {
 9305        use text::ToPoint as _;
 9306
 9307        fn render_relative_row_jump(
 9308            prefix: impl Into<String>,
 9309            current_row: u32,
 9310            target_row: u32,
 9311        ) -> Div {
 9312            let (row_diff, arrow) = if target_row < current_row {
 9313                (current_row - target_row, IconName::ArrowUp)
 9314            } else {
 9315                (target_row - current_row, IconName::ArrowDown)
 9316            };
 9317
 9318            h_flex()
 9319                .child(
 9320                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9321                        .color(Color::Muted)
 9322                        .size(LabelSize::Small),
 9323                )
 9324                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9325        }
 9326
 9327        match &completion.completion {
 9328            InlineCompletion::Move {
 9329                target, snapshot, ..
 9330            } => Some(
 9331                h_flex()
 9332                    .px_2()
 9333                    .gap_2()
 9334                    .flex_1()
 9335                    .child(
 9336                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9337                            Icon::new(IconName::ZedPredictDown)
 9338                        } else {
 9339                            Icon::new(IconName::ZedPredictUp)
 9340                        },
 9341                    )
 9342                    .child(Label::new("Jump to Edit")),
 9343            ),
 9344
 9345            InlineCompletion::Edit {
 9346                edits,
 9347                edit_preview,
 9348                snapshot,
 9349                display_mode: _,
 9350            } => {
 9351                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9352
 9353                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 9354                    &snapshot,
 9355                    &edits,
 9356                    edit_preview.as_ref()?,
 9357                    true,
 9358                    cx,
 9359                )
 9360                .first_line_preview();
 9361
 9362                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9363                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9364
 9365                let preview = h_flex()
 9366                    .gap_1()
 9367                    .min_w_16()
 9368                    .child(styled_text)
 9369                    .when(has_more_lines, |parent| parent.child(""));
 9370
 9371                let left = if first_edit_row != cursor_point.row {
 9372                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9373                        .into_any_element()
 9374                } else {
 9375                    Icon::new(IconName::ZedPredict).into_any_element()
 9376                };
 9377
 9378                Some(
 9379                    h_flex()
 9380                        .h_full()
 9381                        .flex_1()
 9382                        .gap_2()
 9383                        .pr_1()
 9384                        .overflow_x_hidden()
 9385                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9386                        .child(left)
 9387                        .child(preview),
 9388                )
 9389            }
 9390        }
 9391    }
 9392
 9393    pub fn render_context_menu(
 9394        &self,
 9395        style: &EditorStyle,
 9396        max_height_in_lines: u32,
 9397        window: &mut Window,
 9398        cx: &mut Context<Editor>,
 9399    ) -> Option<AnyElement> {
 9400        let menu = self.context_menu.borrow();
 9401        let menu = menu.as_ref()?;
 9402        if !menu.visible() {
 9403            return None;
 9404        };
 9405        Some(menu.render(style, max_height_in_lines, window, cx))
 9406    }
 9407
 9408    fn render_context_menu_aside(
 9409        &mut self,
 9410        max_size: Size<Pixels>,
 9411        window: &mut Window,
 9412        cx: &mut Context<Editor>,
 9413    ) -> Option<AnyElement> {
 9414        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9415            if menu.visible() {
 9416                menu.render_aside(max_size, window, cx)
 9417            } else {
 9418                None
 9419            }
 9420        })
 9421    }
 9422
 9423    fn hide_context_menu(
 9424        &mut self,
 9425        window: &mut Window,
 9426        cx: &mut Context<Self>,
 9427    ) -> Option<CodeContextMenu> {
 9428        cx.notify();
 9429        self.completion_tasks.clear();
 9430        let context_menu = self.context_menu.borrow_mut().take();
 9431        self.stale_inline_completion_in_menu.take();
 9432        self.update_visible_inline_completion(window, cx);
 9433        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9434            if let Some(completion_provider) = &self.completion_provider {
 9435                completion_provider.selection_changed(None, window, cx);
 9436            }
 9437        }
 9438        context_menu
 9439    }
 9440
 9441    fn show_snippet_choices(
 9442        &mut self,
 9443        choices: &Vec<String>,
 9444        selection: Range<Anchor>,
 9445        cx: &mut Context<Self>,
 9446    ) {
 9447        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9448            (Some(a), Some(b)) if a == b => a,
 9449            _ => {
 9450                log::error!("expected anchor range to have matching buffer IDs");
 9451                return;
 9452            }
 9453        };
 9454        let multi_buffer = self.buffer().read(cx);
 9455        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9456            return;
 9457        };
 9458
 9459        let id = post_inc(&mut self.next_completion_id);
 9460        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9461        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9462            CompletionsMenu::new_snippet_choices(
 9463                id,
 9464                true,
 9465                choices,
 9466                selection,
 9467                buffer,
 9468                snippet_sort_order,
 9469            ),
 9470        ));
 9471    }
 9472
 9473    pub fn insert_snippet(
 9474        &mut self,
 9475        insertion_ranges: &[Range<usize>],
 9476        snippet: Snippet,
 9477        window: &mut Window,
 9478        cx: &mut Context<Self>,
 9479    ) -> Result<()> {
 9480        struct Tabstop<T> {
 9481            is_end_tabstop: bool,
 9482            ranges: Vec<Range<T>>,
 9483            choices: Option<Vec<String>>,
 9484        }
 9485
 9486        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9487            let snippet_text: Arc<str> = snippet.text.clone().into();
 9488            let edits = insertion_ranges
 9489                .iter()
 9490                .cloned()
 9491                .map(|range| (range, snippet_text.clone()));
 9492            let autoindent_mode = AutoindentMode::Block {
 9493                original_indent_columns: Vec::new(),
 9494            };
 9495            buffer.edit(edits, Some(autoindent_mode), cx);
 9496
 9497            let snapshot = &*buffer.read(cx);
 9498            let snippet = &snippet;
 9499            snippet
 9500                .tabstops
 9501                .iter()
 9502                .map(|tabstop| {
 9503                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9504                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9505                    });
 9506                    let mut tabstop_ranges = tabstop
 9507                        .ranges
 9508                        .iter()
 9509                        .flat_map(|tabstop_range| {
 9510                            let mut delta = 0_isize;
 9511                            insertion_ranges.iter().map(move |insertion_range| {
 9512                                let insertion_start = insertion_range.start as isize + delta;
 9513                                delta +=
 9514                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9515
 9516                                let start = ((insertion_start + tabstop_range.start) as usize)
 9517                                    .min(snapshot.len());
 9518                                let end = ((insertion_start + tabstop_range.end) as usize)
 9519                                    .min(snapshot.len());
 9520                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9521                            })
 9522                        })
 9523                        .collect::<Vec<_>>();
 9524                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9525
 9526                    Tabstop {
 9527                        is_end_tabstop,
 9528                        ranges: tabstop_ranges,
 9529                        choices: tabstop.choices.clone(),
 9530                    }
 9531                })
 9532                .collect::<Vec<_>>()
 9533        });
 9534        if let Some(tabstop) = tabstops.first() {
 9535            self.change_selections(Default::default(), window, cx, |s| {
 9536                // Reverse order so that the first range is the newest created selection.
 9537                // Completions will use it and autoscroll will prioritize it.
 9538                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9539            });
 9540
 9541            if let Some(choices) = &tabstop.choices {
 9542                if let Some(selection) = tabstop.ranges.first() {
 9543                    self.show_snippet_choices(choices, selection.clone(), cx)
 9544                }
 9545            }
 9546
 9547            // If we're already at the last tabstop and it's at the end of the snippet,
 9548            // we're done, we don't need to keep the state around.
 9549            if !tabstop.is_end_tabstop {
 9550                let choices = tabstops
 9551                    .iter()
 9552                    .map(|tabstop| tabstop.choices.clone())
 9553                    .collect();
 9554
 9555                let ranges = tabstops
 9556                    .into_iter()
 9557                    .map(|tabstop| tabstop.ranges)
 9558                    .collect::<Vec<_>>();
 9559
 9560                self.snippet_stack.push(SnippetState {
 9561                    active_index: 0,
 9562                    ranges,
 9563                    choices,
 9564                });
 9565            }
 9566
 9567            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9568            if self.autoclose_regions.is_empty() {
 9569                let snapshot = self.buffer.read(cx).snapshot(cx);
 9570                let mut all_selections = self.selections.all::<Point>(cx);
 9571                for selection in &mut all_selections {
 9572                    let selection_head = selection.head();
 9573                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9574                        continue;
 9575                    };
 9576
 9577                    let mut bracket_pair = None;
 9578                    let max_lookup_length = scope
 9579                        .brackets()
 9580                        .map(|(pair, _)| {
 9581                            pair.start
 9582                                .as_str()
 9583                                .chars()
 9584                                .count()
 9585                                .max(pair.end.as_str().chars().count())
 9586                        })
 9587                        .max();
 9588                    if let Some(max_lookup_length) = max_lookup_length {
 9589                        let next_text = snapshot
 9590                            .chars_at(selection_head)
 9591                            .take(max_lookup_length)
 9592                            .collect::<String>();
 9593                        let prev_text = snapshot
 9594                            .reversed_chars_at(selection_head)
 9595                            .take(max_lookup_length)
 9596                            .collect::<String>();
 9597
 9598                        for (pair, enabled) in scope.brackets() {
 9599                            if enabled
 9600                                && pair.close
 9601                                && prev_text.starts_with(pair.start.as_str())
 9602                                && next_text.starts_with(pair.end.as_str())
 9603                            {
 9604                                bracket_pair = Some(pair.clone());
 9605                                break;
 9606                            }
 9607                        }
 9608                    }
 9609
 9610                    if let Some(pair) = bracket_pair {
 9611                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9612                        let autoclose_enabled =
 9613                            self.use_autoclose && snapshot_settings.use_autoclose;
 9614                        if autoclose_enabled {
 9615                            let start = snapshot.anchor_after(selection_head);
 9616                            let end = snapshot.anchor_after(selection_head);
 9617                            self.autoclose_regions.push(AutocloseRegion {
 9618                                selection_id: selection.id,
 9619                                range: start..end,
 9620                                pair,
 9621                            });
 9622                        }
 9623                    }
 9624                }
 9625            }
 9626        }
 9627        Ok(())
 9628    }
 9629
 9630    pub fn move_to_next_snippet_tabstop(
 9631        &mut self,
 9632        window: &mut Window,
 9633        cx: &mut Context<Self>,
 9634    ) -> bool {
 9635        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9636    }
 9637
 9638    pub fn move_to_prev_snippet_tabstop(
 9639        &mut self,
 9640        window: &mut Window,
 9641        cx: &mut Context<Self>,
 9642    ) -> bool {
 9643        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9644    }
 9645
 9646    pub fn move_to_snippet_tabstop(
 9647        &mut self,
 9648        bias: Bias,
 9649        window: &mut Window,
 9650        cx: &mut Context<Self>,
 9651    ) -> bool {
 9652        if let Some(mut snippet) = self.snippet_stack.pop() {
 9653            match bias {
 9654                Bias::Left => {
 9655                    if snippet.active_index > 0 {
 9656                        snippet.active_index -= 1;
 9657                    } else {
 9658                        self.snippet_stack.push(snippet);
 9659                        return false;
 9660                    }
 9661                }
 9662                Bias::Right => {
 9663                    if snippet.active_index + 1 < snippet.ranges.len() {
 9664                        snippet.active_index += 1;
 9665                    } else {
 9666                        self.snippet_stack.push(snippet);
 9667                        return false;
 9668                    }
 9669                }
 9670            }
 9671            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9672                self.change_selections(Default::default(), window, cx, |s| {
 9673                    // Reverse order so that the first range is the newest created selection.
 9674                    // Completions will use it and autoscroll will prioritize it.
 9675                    s.select_ranges(current_ranges.iter().rev().cloned())
 9676                });
 9677
 9678                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9679                    if let Some(selection) = current_ranges.first() {
 9680                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9681                    }
 9682                }
 9683
 9684                // If snippet state is not at the last tabstop, push it back on the stack
 9685                if snippet.active_index + 1 < snippet.ranges.len() {
 9686                    self.snippet_stack.push(snippet);
 9687                }
 9688                return true;
 9689            }
 9690        }
 9691
 9692        false
 9693    }
 9694
 9695    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9696        self.transact(window, cx, |this, window, cx| {
 9697            this.select_all(&SelectAll, window, cx);
 9698            this.insert("", window, cx);
 9699        });
 9700    }
 9701
 9702    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9703        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9704        self.transact(window, cx, |this, window, cx| {
 9705            this.select_autoclose_pair(window, cx);
 9706            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9707            if !this.linked_edit_ranges.is_empty() {
 9708                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9709                let snapshot = this.buffer.read(cx).snapshot(cx);
 9710
 9711                for selection in selections.iter() {
 9712                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9713                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9714                    if selection_start.buffer_id != selection_end.buffer_id {
 9715                        continue;
 9716                    }
 9717                    if let Some(ranges) =
 9718                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9719                    {
 9720                        for (buffer, entries) in ranges {
 9721                            linked_ranges.entry(buffer).or_default().extend(entries);
 9722                        }
 9723                    }
 9724                }
 9725            }
 9726
 9727            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9728            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9729            for selection in &mut selections {
 9730                if selection.is_empty() {
 9731                    let old_head = selection.head();
 9732                    let mut new_head =
 9733                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9734                            .to_point(&display_map);
 9735                    if let Some((buffer, line_buffer_range)) = display_map
 9736                        .buffer_snapshot
 9737                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9738                    {
 9739                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9740                        let indent_len = match indent_size.kind {
 9741                            IndentKind::Space => {
 9742                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9743                            }
 9744                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9745                        };
 9746                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9747                            let indent_len = indent_len.get();
 9748                            new_head = cmp::min(
 9749                                new_head,
 9750                                MultiBufferPoint::new(
 9751                                    old_head.row,
 9752                                    ((old_head.column - 1) / indent_len) * indent_len,
 9753                                ),
 9754                            );
 9755                        }
 9756                    }
 9757
 9758                    selection.set_head(new_head, SelectionGoal::None);
 9759                }
 9760            }
 9761
 9762            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9763            this.insert("", window, cx);
 9764            let empty_str: Arc<str> = Arc::from("");
 9765            for (buffer, edits) in linked_ranges {
 9766                let snapshot = buffer.read(cx).snapshot();
 9767                use text::ToPoint as TP;
 9768
 9769                let edits = edits
 9770                    .into_iter()
 9771                    .map(|range| {
 9772                        let end_point = TP::to_point(&range.end, &snapshot);
 9773                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9774
 9775                        if end_point == start_point {
 9776                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9777                                .saturating_sub(1);
 9778                            start_point =
 9779                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9780                        };
 9781
 9782                        (start_point..end_point, empty_str.clone())
 9783                    })
 9784                    .sorted_by_key(|(range, _)| range.start)
 9785                    .collect::<Vec<_>>();
 9786                buffer.update(cx, |this, cx| {
 9787                    this.edit(edits, None, cx);
 9788                })
 9789            }
 9790            this.refresh_inline_completion(true, false, window, cx);
 9791            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9792        });
 9793    }
 9794
 9795    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9796        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9797        self.transact(window, cx, |this, window, cx| {
 9798            this.change_selections(Default::default(), window, cx, |s| {
 9799                s.move_with(|map, selection| {
 9800                    if selection.is_empty() {
 9801                        let cursor = movement::right(map, selection.head());
 9802                        selection.end = cursor;
 9803                        selection.reversed = true;
 9804                        selection.goal = SelectionGoal::None;
 9805                    }
 9806                })
 9807            });
 9808            this.insert("", window, cx);
 9809            this.refresh_inline_completion(true, false, window, cx);
 9810        });
 9811    }
 9812
 9813    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9814        if self.mode.is_single_line() {
 9815            cx.propagate();
 9816            return;
 9817        }
 9818
 9819        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9820        if self.move_to_prev_snippet_tabstop(window, cx) {
 9821            return;
 9822        }
 9823        self.outdent(&Outdent, window, cx);
 9824    }
 9825
 9826    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9827        if self.mode.is_single_line() {
 9828            cx.propagate();
 9829            return;
 9830        }
 9831
 9832        if self.move_to_next_snippet_tabstop(window, cx) {
 9833            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9834            return;
 9835        }
 9836        if self.read_only(cx) {
 9837            return;
 9838        }
 9839        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9840        let mut selections = self.selections.all_adjusted(cx);
 9841        let buffer = self.buffer.read(cx);
 9842        let snapshot = buffer.snapshot(cx);
 9843        let rows_iter = selections.iter().map(|s| s.head().row);
 9844        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9845
 9846        let has_some_cursor_in_whitespace = selections
 9847            .iter()
 9848            .filter(|selection| selection.is_empty())
 9849            .any(|selection| {
 9850                let cursor = selection.head();
 9851                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9852                cursor.column < current_indent.len
 9853            });
 9854
 9855        let mut edits = Vec::new();
 9856        let mut prev_edited_row = 0;
 9857        let mut row_delta = 0;
 9858        for selection in &mut selections {
 9859            if selection.start.row != prev_edited_row {
 9860                row_delta = 0;
 9861            }
 9862            prev_edited_row = selection.end.row;
 9863
 9864            // If the selection is non-empty, then increase the indentation of the selected lines.
 9865            if !selection.is_empty() {
 9866                row_delta =
 9867                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9868                continue;
 9869            }
 9870
 9871            let cursor = selection.head();
 9872            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9873            if let Some(suggested_indent) =
 9874                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9875            {
 9876                // Don't do anything if already at suggested indent
 9877                // and there is any other cursor which is not
 9878                if has_some_cursor_in_whitespace
 9879                    && cursor.column == current_indent.len
 9880                    && current_indent.len == suggested_indent.len
 9881                {
 9882                    continue;
 9883                }
 9884
 9885                // Adjust line and move cursor to suggested indent
 9886                // if cursor is not at suggested indent
 9887                if cursor.column < suggested_indent.len
 9888                    && cursor.column <= current_indent.len
 9889                    && current_indent.len <= suggested_indent.len
 9890                {
 9891                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9892                    selection.end = selection.start;
 9893                    if row_delta == 0 {
 9894                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9895                            cursor.row,
 9896                            current_indent,
 9897                            suggested_indent,
 9898                        ));
 9899                        row_delta = suggested_indent.len - current_indent.len;
 9900                    }
 9901                    continue;
 9902                }
 9903
 9904                // If current indent is more than suggested indent
 9905                // only move cursor to current indent and skip indent
 9906                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9907                    selection.start = Point::new(cursor.row, current_indent.len);
 9908                    selection.end = selection.start;
 9909                    continue;
 9910                }
 9911            }
 9912
 9913            // Otherwise, insert a hard or soft tab.
 9914            let settings = buffer.language_settings_at(cursor, cx);
 9915            let tab_size = if settings.hard_tabs {
 9916                IndentSize::tab()
 9917            } else {
 9918                let tab_size = settings.tab_size.get();
 9919                let indent_remainder = snapshot
 9920                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9921                    .flat_map(str::chars)
 9922                    .fold(row_delta % tab_size, |counter: u32, c| {
 9923                        if c == '\t' {
 9924                            0
 9925                        } else {
 9926                            (counter + 1) % tab_size
 9927                        }
 9928                    });
 9929
 9930                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9931                IndentSize::spaces(chars_to_next_tab_stop)
 9932            };
 9933            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9934            selection.end = selection.start;
 9935            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9936            row_delta += tab_size.len;
 9937        }
 9938
 9939        self.transact(window, cx, |this, window, cx| {
 9940            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9941            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9942            this.refresh_inline_completion(true, false, window, cx);
 9943        });
 9944    }
 9945
 9946    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9947        if self.read_only(cx) {
 9948            return;
 9949        }
 9950        if self.mode.is_single_line() {
 9951            cx.propagate();
 9952            return;
 9953        }
 9954
 9955        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9956        let mut selections = self.selections.all::<Point>(cx);
 9957        let mut prev_edited_row = 0;
 9958        let mut row_delta = 0;
 9959        let mut edits = Vec::new();
 9960        let buffer = self.buffer.read(cx);
 9961        let snapshot = buffer.snapshot(cx);
 9962        for selection in &mut selections {
 9963            if selection.start.row != prev_edited_row {
 9964                row_delta = 0;
 9965            }
 9966            prev_edited_row = selection.end.row;
 9967
 9968            row_delta =
 9969                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9970        }
 9971
 9972        self.transact(window, cx, |this, window, cx| {
 9973            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9974            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9975        });
 9976    }
 9977
 9978    fn indent_selection(
 9979        buffer: &MultiBuffer,
 9980        snapshot: &MultiBufferSnapshot,
 9981        selection: &mut Selection<Point>,
 9982        edits: &mut Vec<(Range<Point>, String)>,
 9983        delta_for_start_row: u32,
 9984        cx: &App,
 9985    ) -> u32 {
 9986        let settings = buffer.language_settings_at(selection.start, cx);
 9987        let tab_size = settings.tab_size.get();
 9988        let indent_kind = if settings.hard_tabs {
 9989            IndentKind::Tab
 9990        } else {
 9991            IndentKind::Space
 9992        };
 9993        let mut start_row = selection.start.row;
 9994        let mut end_row = selection.end.row + 1;
 9995
 9996        // If a selection ends at the beginning of a line, don't indent
 9997        // that last line.
 9998        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9999            end_row -= 1;
10000        }
10001
10002        // Avoid re-indenting a row that has already been indented by a
10003        // previous selection, but still update this selection's column
10004        // to reflect that indentation.
10005        if delta_for_start_row > 0 {
10006            start_row += 1;
10007            selection.start.column += delta_for_start_row;
10008            if selection.end.row == selection.start.row {
10009                selection.end.column += delta_for_start_row;
10010            }
10011        }
10012
10013        let mut delta_for_end_row = 0;
10014        let has_multiple_rows = start_row + 1 != end_row;
10015        for row in start_row..end_row {
10016            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10017            let indent_delta = match (current_indent.kind, indent_kind) {
10018                (IndentKind::Space, IndentKind::Space) => {
10019                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10020                    IndentSize::spaces(columns_to_next_tab_stop)
10021                }
10022                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10023                (_, IndentKind::Tab) => IndentSize::tab(),
10024            };
10025
10026            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10027                0
10028            } else {
10029                selection.start.column
10030            };
10031            let row_start = Point::new(row, start);
10032            edits.push((
10033                row_start..row_start,
10034                indent_delta.chars().collect::<String>(),
10035            ));
10036
10037            // Update this selection's endpoints to reflect the indentation.
10038            if row == selection.start.row {
10039                selection.start.column += indent_delta.len;
10040            }
10041            if row == selection.end.row {
10042                selection.end.column += indent_delta.len;
10043                delta_for_end_row = indent_delta.len;
10044            }
10045        }
10046
10047        if selection.start.row == selection.end.row {
10048            delta_for_start_row + delta_for_end_row
10049        } else {
10050            delta_for_end_row
10051        }
10052    }
10053
10054    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10055        if self.read_only(cx) {
10056            return;
10057        }
10058        if self.mode.is_single_line() {
10059            cx.propagate();
10060            return;
10061        }
10062
10063        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10064        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10065        let selections = self.selections.all::<Point>(cx);
10066        let mut deletion_ranges = Vec::new();
10067        let mut last_outdent = None;
10068        {
10069            let buffer = self.buffer.read(cx);
10070            let snapshot = buffer.snapshot(cx);
10071            for selection in &selections {
10072                let settings = buffer.language_settings_at(selection.start, cx);
10073                let tab_size = settings.tab_size.get();
10074                let mut rows = selection.spanned_rows(false, &display_map);
10075
10076                // Avoid re-outdenting a row that has already been outdented by a
10077                // previous selection.
10078                if let Some(last_row) = last_outdent {
10079                    if last_row == rows.start {
10080                        rows.start = rows.start.next_row();
10081                    }
10082                }
10083                let has_multiple_rows = rows.len() > 1;
10084                for row in rows.iter_rows() {
10085                    let indent_size = snapshot.indent_size_for_line(row);
10086                    if indent_size.len > 0 {
10087                        let deletion_len = match indent_size.kind {
10088                            IndentKind::Space => {
10089                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10090                                if columns_to_prev_tab_stop == 0 {
10091                                    tab_size
10092                                } else {
10093                                    columns_to_prev_tab_stop
10094                                }
10095                            }
10096                            IndentKind::Tab => 1,
10097                        };
10098                        let start = if has_multiple_rows
10099                            || deletion_len > selection.start.column
10100                            || indent_size.len < selection.start.column
10101                        {
10102                            0
10103                        } else {
10104                            selection.start.column - deletion_len
10105                        };
10106                        deletion_ranges.push(
10107                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10108                        );
10109                        last_outdent = Some(row);
10110                    }
10111                }
10112            }
10113        }
10114
10115        self.transact(window, cx, |this, window, cx| {
10116            this.buffer.update(cx, |buffer, cx| {
10117                let empty_str: Arc<str> = Arc::default();
10118                buffer.edit(
10119                    deletion_ranges
10120                        .into_iter()
10121                        .map(|range| (range, empty_str.clone())),
10122                    None,
10123                    cx,
10124                );
10125            });
10126            let selections = this.selections.all::<usize>(cx);
10127            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10128        });
10129    }
10130
10131    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10132        if self.read_only(cx) {
10133            return;
10134        }
10135        if self.mode.is_single_line() {
10136            cx.propagate();
10137            return;
10138        }
10139
10140        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10141        let selections = self
10142            .selections
10143            .all::<usize>(cx)
10144            .into_iter()
10145            .map(|s| s.range());
10146
10147        self.transact(window, cx, |this, window, cx| {
10148            this.buffer.update(cx, |buffer, cx| {
10149                buffer.autoindent_ranges(selections, cx);
10150            });
10151            let selections = this.selections.all::<usize>(cx);
10152            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10153        });
10154    }
10155
10156    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10157        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10158        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10159        let selections = self.selections.all::<Point>(cx);
10160
10161        let mut new_cursors = Vec::new();
10162        let mut edit_ranges = Vec::new();
10163        let mut selections = selections.iter().peekable();
10164        while let Some(selection) = selections.next() {
10165            let mut rows = selection.spanned_rows(false, &display_map);
10166            let goal_display_column = selection.head().to_display_point(&display_map).column();
10167
10168            // Accumulate contiguous regions of rows that we want to delete.
10169            while let Some(next_selection) = selections.peek() {
10170                let next_rows = next_selection.spanned_rows(false, &display_map);
10171                if next_rows.start <= rows.end {
10172                    rows.end = next_rows.end;
10173                    selections.next().unwrap();
10174                } else {
10175                    break;
10176                }
10177            }
10178
10179            let buffer = &display_map.buffer_snapshot;
10180            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10181            let edit_end;
10182            let cursor_buffer_row;
10183            if buffer.max_point().row >= rows.end.0 {
10184                // If there's a line after the range, delete the \n from the end of the row range
10185                // and position the cursor on the next line.
10186                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10187                cursor_buffer_row = rows.end;
10188            } else {
10189                // If there isn't a line after the range, delete the \n from the line before the
10190                // start of the row range and position the cursor there.
10191                edit_start = edit_start.saturating_sub(1);
10192                edit_end = buffer.len();
10193                cursor_buffer_row = rows.start.previous_row();
10194            }
10195
10196            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10197            *cursor.column_mut() =
10198                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10199
10200            new_cursors.push((
10201                selection.id,
10202                buffer.anchor_after(cursor.to_point(&display_map)),
10203            ));
10204            edit_ranges.push(edit_start..edit_end);
10205        }
10206
10207        self.transact(window, cx, |this, window, cx| {
10208            let buffer = this.buffer.update(cx, |buffer, cx| {
10209                let empty_str: Arc<str> = Arc::default();
10210                buffer.edit(
10211                    edit_ranges
10212                        .into_iter()
10213                        .map(|range| (range, empty_str.clone())),
10214                    None,
10215                    cx,
10216                );
10217                buffer.snapshot(cx)
10218            });
10219            let new_selections = new_cursors
10220                .into_iter()
10221                .map(|(id, cursor)| {
10222                    let cursor = cursor.to_point(&buffer);
10223                    Selection {
10224                        id,
10225                        start: cursor,
10226                        end: cursor,
10227                        reversed: false,
10228                        goal: SelectionGoal::None,
10229                    }
10230                })
10231                .collect();
10232
10233            this.change_selections(Default::default(), window, cx, |s| {
10234                s.select(new_selections);
10235            });
10236        });
10237    }
10238
10239    pub fn join_lines_impl(
10240        &mut self,
10241        insert_whitespace: bool,
10242        window: &mut Window,
10243        cx: &mut Context<Self>,
10244    ) {
10245        if self.read_only(cx) {
10246            return;
10247        }
10248        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10249        for selection in self.selections.all::<Point>(cx) {
10250            let start = MultiBufferRow(selection.start.row);
10251            // Treat single line selections as if they include the next line. Otherwise this action
10252            // would do nothing for single line selections individual cursors.
10253            let end = if selection.start.row == selection.end.row {
10254                MultiBufferRow(selection.start.row + 1)
10255            } else {
10256                MultiBufferRow(selection.end.row)
10257            };
10258
10259            if let Some(last_row_range) = row_ranges.last_mut() {
10260                if start <= last_row_range.end {
10261                    last_row_range.end = end;
10262                    continue;
10263                }
10264            }
10265            row_ranges.push(start..end);
10266        }
10267
10268        let snapshot = self.buffer.read(cx).snapshot(cx);
10269        let mut cursor_positions = Vec::new();
10270        for row_range in &row_ranges {
10271            let anchor = snapshot.anchor_before(Point::new(
10272                row_range.end.previous_row().0,
10273                snapshot.line_len(row_range.end.previous_row()),
10274            ));
10275            cursor_positions.push(anchor..anchor);
10276        }
10277
10278        self.transact(window, cx, |this, window, cx| {
10279            for row_range in row_ranges.into_iter().rev() {
10280                for row in row_range.iter_rows().rev() {
10281                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10282                    let next_line_row = row.next_row();
10283                    let indent = snapshot.indent_size_for_line(next_line_row);
10284                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10285
10286                    let replace =
10287                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10288                            " "
10289                        } else {
10290                            ""
10291                        };
10292
10293                    this.buffer.update(cx, |buffer, cx| {
10294                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10295                    });
10296                }
10297            }
10298
10299            this.change_selections(Default::default(), window, cx, |s| {
10300                s.select_anchor_ranges(cursor_positions)
10301            });
10302        });
10303    }
10304
10305    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10306        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10307        self.join_lines_impl(true, window, cx);
10308    }
10309
10310    pub fn sort_lines_case_sensitive(
10311        &mut self,
10312        _: &SortLinesCaseSensitive,
10313        window: &mut Window,
10314        cx: &mut Context<Self>,
10315    ) {
10316        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10317    }
10318
10319    pub fn sort_lines_by_length(
10320        &mut self,
10321        _: &SortLinesByLength,
10322        window: &mut Window,
10323        cx: &mut Context<Self>,
10324    ) {
10325        self.manipulate_immutable_lines(window, cx, |lines| {
10326            lines.sort_by_key(|&line| line.chars().count())
10327        })
10328    }
10329
10330    pub fn sort_lines_case_insensitive(
10331        &mut self,
10332        _: &SortLinesCaseInsensitive,
10333        window: &mut Window,
10334        cx: &mut Context<Self>,
10335    ) {
10336        self.manipulate_immutable_lines(window, cx, |lines| {
10337            lines.sort_by_key(|line| line.to_lowercase())
10338        })
10339    }
10340
10341    pub fn unique_lines_case_insensitive(
10342        &mut self,
10343        _: &UniqueLinesCaseInsensitive,
10344        window: &mut Window,
10345        cx: &mut Context<Self>,
10346    ) {
10347        self.manipulate_immutable_lines(window, cx, |lines| {
10348            let mut seen = HashSet::default();
10349            lines.retain(|line| seen.insert(line.to_lowercase()));
10350        })
10351    }
10352
10353    pub fn unique_lines_case_sensitive(
10354        &mut self,
10355        _: &UniqueLinesCaseSensitive,
10356        window: &mut Window,
10357        cx: &mut Context<Self>,
10358    ) {
10359        self.manipulate_immutable_lines(window, cx, |lines| {
10360            let mut seen = HashSet::default();
10361            lines.retain(|line| seen.insert(*line));
10362        })
10363    }
10364
10365    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10366        let Some(project) = self.project.clone() else {
10367            return;
10368        };
10369        self.reload(project, window, cx)
10370            .detach_and_notify_err(window, cx);
10371    }
10372
10373    pub fn restore_file(
10374        &mut self,
10375        _: &::git::RestoreFile,
10376        window: &mut Window,
10377        cx: &mut Context<Self>,
10378    ) {
10379        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10380        let mut buffer_ids = HashSet::default();
10381        let snapshot = self.buffer().read(cx).snapshot(cx);
10382        for selection in self.selections.all::<usize>(cx) {
10383            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10384        }
10385
10386        let buffer = self.buffer().read(cx);
10387        let ranges = buffer_ids
10388            .into_iter()
10389            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10390            .collect::<Vec<_>>();
10391
10392        self.restore_hunks_in_ranges(ranges, window, cx);
10393    }
10394
10395    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10396        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10397        let selections = self
10398            .selections
10399            .all(cx)
10400            .into_iter()
10401            .map(|s| s.range())
10402            .collect();
10403        self.restore_hunks_in_ranges(selections, window, cx);
10404    }
10405
10406    pub fn restore_hunks_in_ranges(
10407        &mut self,
10408        ranges: Vec<Range<Point>>,
10409        window: &mut Window,
10410        cx: &mut Context<Editor>,
10411    ) {
10412        let mut revert_changes = HashMap::default();
10413        let chunk_by = self
10414            .snapshot(window, cx)
10415            .hunks_for_ranges(ranges)
10416            .into_iter()
10417            .chunk_by(|hunk| hunk.buffer_id);
10418        for (buffer_id, hunks) in &chunk_by {
10419            let hunks = hunks.collect::<Vec<_>>();
10420            for hunk in &hunks {
10421                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10422            }
10423            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10424        }
10425        drop(chunk_by);
10426        if !revert_changes.is_empty() {
10427            self.transact(window, cx, |editor, window, cx| {
10428                editor.restore(revert_changes, window, cx);
10429            });
10430        }
10431    }
10432
10433    pub fn open_active_item_in_terminal(
10434        &mut self,
10435        _: &OpenInTerminal,
10436        window: &mut Window,
10437        cx: &mut Context<Self>,
10438    ) {
10439        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10440            let project_path = buffer.read(cx).project_path(cx)?;
10441            let project = self.project.as_ref()?.read(cx);
10442            let entry = project.entry_for_path(&project_path, cx)?;
10443            let parent = match &entry.canonical_path {
10444                Some(canonical_path) => canonical_path.to_path_buf(),
10445                None => project.absolute_path(&project_path, cx)?,
10446            }
10447            .parent()?
10448            .to_path_buf();
10449            Some(parent)
10450        }) {
10451            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10452        }
10453    }
10454
10455    fn set_breakpoint_context_menu(
10456        &mut self,
10457        display_row: DisplayRow,
10458        position: Option<Anchor>,
10459        clicked_point: gpui::Point<Pixels>,
10460        window: &mut Window,
10461        cx: &mut Context<Self>,
10462    ) {
10463        let source = self
10464            .buffer
10465            .read(cx)
10466            .snapshot(cx)
10467            .anchor_before(Point::new(display_row.0, 0u32));
10468
10469        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10470
10471        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10472            self,
10473            source,
10474            clicked_point,
10475            context_menu,
10476            window,
10477            cx,
10478        );
10479    }
10480
10481    fn add_edit_breakpoint_block(
10482        &mut self,
10483        anchor: Anchor,
10484        breakpoint: &Breakpoint,
10485        edit_action: BreakpointPromptEditAction,
10486        window: &mut Window,
10487        cx: &mut Context<Self>,
10488    ) {
10489        let weak_editor = cx.weak_entity();
10490        let bp_prompt = cx.new(|cx| {
10491            BreakpointPromptEditor::new(
10492                weak_editor,
10493                anchor,
10494                breakpoint.clone(),
10495                edit_action,
10496                window,
10497                cx,
10498            )
10499        });
10500
10501        let height = bp_prompt.update(cx, |this, cx| {
10502            this.prompt
10503                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10504        });
10505        let cloned_prompt = bp_prompt.clone();
10506        let blocks = vec![BlockProperties {
10507            style: BlockStyle::Sticky,
10508            placement: BlockPlacement::Above(anchor),
10509            height: Some(height),
10510            render: Arc::new(move |cx| {
10511                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10512                cloned_prompt.clone().into_any_element()
10513            }),
10514            priority: 0,
10515        }];
10516
10517        let focus_handle = bp_prompt.focus_handle(cx);
10518        window.focus(&focus_handle);
10519
10520        let block_ids = self.insert_blocks(blocks, None, cx);
10521        bp_prompt.update(cx, |prompt, _| {
10522            prompt.add_block_ids(block_ids);
10523        });
10524    }
10525
10526    pub(crate) fn breakpoint_at_row(
10527        &self,
10528        row: u32,
10529        window: &mut Window,
10530        cx: &mut Context<Self>,
10531    ) -> Option<(Anchor, Breakpoint)> {
10532        let snapshot = self.snapshot(window, cx);
10533        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10534
10535        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10536    }
10537
10538    pub(crate) fn breakpoint_at_anchor(
10539        &self,
10540        breakpoint_position: Anchor,
10541        snapshot: &EditorSnapshot,
10542        cx: &mut Context<Self>,
10543    ) -> Option<(Anchor, Breakpoint)> {
10544        let project = self.project.clone()?;
10545
10546        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10547            snapshot
10548                .buffer_snapshot
10549                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10550        })?;
10551
10552        let enclosing_excerpt = breakpoint_position.excerpt_id;
10553        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10554        let buffer_snapshot = buffer.read(cx).snapshot();
10555
10556        let row = buffer_snapshot
10557            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10558            .row;
10559
10560        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10561        let anchor_end = snapshot
10562            .buffer_snapshot
10563            .anchor_after(Point::new(row, line_len));
10564
10565        let bp = self
10566            .breakpoint_store
10567            .as_ref()?
10568            .read_with(cx, |breakpoint_store, cx| {
10569                breakpoint_store
10570                    .breakpoints(
10571                        &buffer,
10572                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10573                        &buffer_snapshot,
10574                        cx,
10575                    )
10576                    .next()
10577                    .and_then(|(bp, _)| {
10578                        let breakpoint_row = buffer_snapshot
10579                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10580                            .row;
10581
10582                        if breakpoint_row == row {
10583                            snapshot
10584                                .buffer_snapshot
10585                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10586                                .map(|position| (position, bp.bp.clone()))
10587                        } else {
10588                            None
10589                        }
10590                    })
10591            });
10592        bp
10593    }
10594
10595    pub fn edit_log_breakpoint(
10596        &mut self,
10597        _: &EditLogBreakpoint,
10598        window: &mut Window,
10599        cx: &mut Context<Self>,
10600    ) {
10601        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10602            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10603                message: None,
10604                state: BreakpointState::Enabled,
10605                condition: None,
10606                hit_condition: None,
10607            });
10608
10609            self.add_edit_breakpoint_block(
10610                anchor,
10611                &breakpoint,
10612                BreakpointPromptEditAction::Log,
10613                window,
10614                cx,
10615            );
10616        }
10617    }
10618
10619    fn breakpoints_at_cursors(
10620        &self,
10621        window: &mut Window,
10622        cx: &mut Context<Self>,
10623    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10624        let snapshot = self.snapshot(window, cx);
10625        let cursors = self
10626            .selections
10627            .disjoint_anchors()
10628            .into_iter()
10629            .map(|selection| {
10630                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10631
10632                let breakpoint_position = self
10633                    .breakpoint_at_row(cursor_position.row, window, cx)
10634                    .map(|bp| bp.0)
10635                    .unwrap_or_else(|| {
10636                        snapshot
10637                            .display_snapshot
10638                            .buffer_snapshot
10639                            .anchor_after(Point::new(cursor_position.row, 0))
10640                    });
10641
10642                let breakpoint = self
10643                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10644                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10645
10646                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10647            })
10648            // 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.
10649            .collect::<HashMap<Anchor, _>>();
10650
10651        cursors.into_iter().collect()
10652    }
10653
10654    pub fn enable_breakpoint(
10655        &mut self,
10656        _: &crate::actions::EnableBreakpoint,
10657        window: &mut Window,
10658        cx: &mut Context<Self>,
10659    ) {
10660        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10661            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10662                continue;
10663            };
10664            self.edit_breakpoint_at_anchor(
10665                anchor,
10666                breakpoint,
10667                BreakpointEditAction::InvertState,
10668                cx,
10669            );
10670        }
10671    }
10672
10673    pub fn disable_breakpoint(
10674        &mut self,
10675        _: &crate::actions::DisableBreakpoint,
10676        window: &mut Window,
10677        cx: &mut Context<Self>,
10678    ) {
10679        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10680            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10681                continue;
10682            };
10683            self.edit_breakpoint_at_anchor(
10684                anchor,
10685                breakpoint,
10686                BreakpointEditAction::InvertState,
10687                cx,
10688            );
10689        }
10690    }
10691
10692    pub fn toggle_breakpoint(
10693        &mut self,
10694        _: &crate::actions::ToggleBreakpoint,
10695        window: &mut Window,
10696        cx: &mut Context<Self>,
10697    ) {
10698        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10699            if let Some(breakpoint) = breakpoint {
10700                self.edit_breakpoint_at_anchor(
10701                    anchor,
10702                    breakpoint,
10703                    BreakpointEditAction::Toggle,
10704                    cx,
10705                );
10706            } else {
10707                self.edit_breakpoint_at_anchor(
10708                    anchor,
10709                    Breakpoint::new_standard(),
10710                    BreakpointEditAction::Toggle,
10711                    cx,
10712                );
10713            }
10714        }
10715    }
10716
10717    pub fn edit_breakpoint_at_anchor(
10718        &mut self,
10719        breakpoint_position: Anchor,
10720        breakpoint: Breakpoint,
10721        edit_action: BreakpointEditAction,
10722        cx: &mut Context<Self>,
10723    ) {
10724        let Some(breakpoint_store) = &self.breakpoint_store else {
10725            return;
10726        };
10727
10728        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10729            if breakpoint_position == Anchor::min() {
10730                self.buffer()
10731                    .read(cx)
10732                    .excerpt_buffer_ids()
10733                    .into_iter()
10734                    .next()
10735            } else {
10736                None
10737            }
10738        }) else {
10739            return;
10740        };
10741
10742        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10743            return;
10744        };
10745
10746        breakpoint_store.update(cx, |breakpoint_store, cx| {
10747            breakpoint_store.toggle_breakpoint(
10748                buffer,
10749                BreakpointWithPosition {
10750                    position: breakpoint_position.text_anchor,
10751                    bp: breakpoint,
10752                },
10753                edit_action,
10754                cx,
10755            );
10756        });
10757
10758        cx.notify();
10759    }
10760
10761    #[cfg(any(test, feature = "test-support"))]
10762    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10763        self.breakpoint_store.clone()
10764    }
10765
10766    pub fn prepare_restore_change(
10767        &self,
10768        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10769        hunk: &MultiBufferDiffHunk,
10770        cx: &mut App,
10771    ) -> Option<()> {
10772        if hunk.is_created_file() {
10773            return None;
10774        }
10775        let buffer = self.buffer.read(cx);
10776        let diff = buffer.diff_for(hunk.buffer_id)?;
10777        let buffer = buffer.buffer(hunk.buffer_id)?;
10778        let buffer = buffer.read(cx);
10779        let original_text = diff
10780            .read(cx)
10781            .base_text()
10782            .as_rope()
10783            .slice(hunk.diff_base_byte_range.clone());
10784        let buffer_snapshot = buffer.snapshot();
10785        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10786        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10787            probe
10788                .0
10789                .start
10790                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10791                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10792        }) {
10793            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10794            Some(())
10795        } else {
10796            None
10797        }
10798    }
10799
10800    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10801        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10802    }
10803
10804    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10805        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10806    }
10807
10808    fn manipulate_lines<M>(
10809        &mut self,
10810        window: &mut Window,
10811        cx: &mut Context<Self>,
10812        mut manipulate: M,
10813    ) where
10814        M: FnMut(&str) -> LineManipulationResult,
10815    {
10816        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10817
10818        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10819        let buffer = self.buffer.read(cx).snapshot(cx);
10820
10821        let mut edits = Vec::new();
10822
10823        let selections = self.selections.all::<Point>(cx);
10824        let mut selections = selections.iter().peekable();
10825        let mut contiguous_row_selections = Vec::new();
10826        let mut new_selections = Vec::new();
10827        let mut added_lines = 0;
10828        let mut removed_lines = 0;
10829
10830        while let Some(selection) = selections.next() {
10831            let (start_row, end_row) = consume_contiguous_rows(
10832                &mut contiguous_row_selections,
10833                selection,
10834                &display_map,
10835                &mut selections,
10836            );
10837
10838            let start_point = Point::new(start_row.0, 0);
10839            let end_point = Point::new(
10840                end_row.previous_row().0,
10841                buffer.line_len(end_row.previous_row()),
10842            );
10843            let text = buffer
10844                .text_for_range(start_point..end_point)
10845                .collect::<String>();
10846
10847            let LineManipulationResult {
10848                new_text,
10849                line_count_before,
10850                line_count_after,
10851            } = manipulate(&text);
10852
10853            edits.push((start_point..end_point, new_text));
10854
10855            // Selections must change based on added and removed line count
10856            let start_row =
10857                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10858            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10859            new_selections.push(Selection {
10860                id: selection.id,
10861                start: start_row,
10862                end: end_row,
10863                goal: SelectionGoal::None,
10864                reversed: selection.reversed,
10865            });
10866
10867            if line_count_after > line_count_before {
10868                added_lines += line_count_after - line_count_before;
10869            } else if line_count_before > line_count_after {
10870                removed_lines += line_count_before - line_count_after;
10871            }
10872        }
10873
10874        self.transact(window, cx, |this, window, cx| {
10875            let buffer = this.buffer.update(cx, |buffer, cx| {
10876                buffer.edit(edits, None, cx);
10877                buffer.snapshot(cx)
10878            });
10879
10880            // Recalculate offsets on newly edited buffer
10881            let new_selections = new_selections
10882                .iter()
10883                .map(|s| {
10884                    let start_point = Point::new(s.start.0, 0);
10885                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10886                    Selection {
10887                        id: s.id,
10888                        start: buffer.point_to_offset(start_point),
10889                        end: buffer.point_to_offset(end_point),
10890                        goal: s.goal,
10891                        reversed: s.reversed,
10892                    }
10893                })
10894                .collect();
10895
10896            this.change_selections(Default::default(), window, cx, |s| {
10897                s.select(new_selections);
10898            });
10899
10900            this.request_autoscroll(Autoscroll::fit(), cx);
10901        });
10902    }
10903
10904    fn manipulate_immutable_lines<Fn>(
10905        &mut self,
10906        window: &mut Window,
10907        cx: &mut Context<Self>,
10908        mut callback: Fn,
10909    ) where
10910        Fn: FnMut(&mut Vec<&str>),
10911    {
10912        self.manipulate_lines(window, cx, |text| {
10913            let mut lines: Vec<&str> = text.split('\n').collect();
10914            let line_count_before = lines.len();
10915
10916            callback(&mut lines);
10917
10918            LineManipulationResult {
10919                new_text: lines.join("\n"),
10920                line_count_before,
10921                line_count_after: lines.len(),
10922            }
10923        });
10924    }
10925
10926    fn manipulate_mutable_lines<Fn>(
10927        &mut self,
10928        window: &mut Window,
10929        cx: &mut Context<Self>,
10930        mut callback: Fn,
10931    ) where
10932        Fn: FnMut(&mut Vec<Cow<'_, str>>),
10933    {
10934        self.manipulate_lines(window, cx, |text| {
10935            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
10936            let line_count_before = lines.len();
10937
10938            callback(&mut lines);
10939
10940            LineManipulationResult {
10941                new_text: lines.join("\n"),
10942                line_count_before,
10943                line_count_after: lines.len(),
10944            }
10945        });
10946    }
10947
10948    pub fn convert_indentation_to_spaces(
10949        &mut self,
10950        _: &ConvertIndentationToSpaces,
10951        window: &mut Window,
10952        cx: &mut Context<Self>,
10953    ) {
10954        let settings = self.buffer.read(cx).language_settings(cx);
10955        let tab_size = settings.tab_size.get() as usize;
10956
10957        self.manipulate_mutable_lines(window, cx, |lines| {
10958            // Allocates a reasonably sized scratch buffer once for the whole loop
10959            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10960            // Avoids recomputing spaces that could be inserted many times
10961            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10962                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10963                .collect();
10964
10965            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10966                let mut chars = line.as_ref().chars();
10967                let mut col = 0;
10968                let mut changed = false;
10969
10970                while let Some(ch) = chars.next() {
10971                    match ch {
10972                        ' ' => {
10973                            reindented_line.push(' ');
10974                            col += 1;
10975                        }
10976                        '\t' => {
10977                            // \t are converted to spaces depending on the current column
10978                            let spaces_len = tab_size - (col % tab_size);
10979                            reindented_line.extend(&space_cache[spaces_len - 1]);
10980                            col += spaces_len;
10981                            changed = true;
10982                        }
10983                        _ => {
10984                            // If we dont append before break, the character is consumed
10985                            reindented_line.push(ch);
10986                            break;
10987                        }
10988                    }
10989                }
10990
10991                if !changed {
10992                    reindented_line.clear();
10993                    continue;
10994                }
10995                // Append the rest of the line and replace old reference with new one
10996                reindented_line.extend(chars);
10997                *line = Cow::Owned(reindented_line.clone());
10998                reindented_line.clear();
10999            }
11000        });
11001    }
11002
11003    pub fn convert_indentation_to_tabs(
11004        &mut self,
11005        _: &ConvertIndentationToTabs,
11006        window: &mut Window,
11007        cx: &mut Context<Self>,
11008    ) {
11009        let settings = self.buffer.read(cx).language_settings(cx);
11010        let tab_size = settings.tab_size.get() as usize;
11011
11012        self.manipulate_mutable_lines(window, cx, |lines| {
11013            // Allocates a reasonably sized buffer once for the whole loop
11014            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11015            // Avoids recomputing spaces that could be inserted many times
11016            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11017                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11018                .collect();
11019
11020            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11021                let mut chars = line.chars();
11022                let mut spaces_count = 0;
11023                let mut first_non_indent_char = None;
11024                let mut changed = false;
11025
11026                while let Some(ch) = chars.next() {
11027                    match ch {
11028                        ' ' => {
11029                            // Keep track of spaces. Append \t when we reach tab_size
11030                            spaces_count += 1;
11031                            changed = true;
11032                            if spaces_count == tab_size {
11033                                reindented_line.push('\t');
11034                                spaces_count = 0;
11035                            }
11036                        }
11037                        '\t' => {
11038                            reindented_line.push('\t');
11039                            spaces_count = 0;
11040                        }
11041                        _ => {
11042                            // Dont append it yet, we might have remaining spaces
11043                            first_non_indent_char = Some(ch);
11044                            break;
11045                        }
11046                    }
11047                }
11048
11049                if !changed {
11050                    reindented_line.clear();
11051                    continue;
11052                }
11053                // Remaining spaces that didn't make a full tab stop
11054                if spaces_count > 0 {
11055                    reindented_line.extend(&space_cache[spaces_count - 1]);
11056                }
11057                // If we consume an extra character that was not indentation, add it back
11058                if let Some(extra_char) = first_non_indent_char {
11059                    reindented_line.push(extra_char);
11060                }
11061                // Append the rest of the line and replace old reference with new one
11062                reindented_line.extend(chars);
11063                *line = Cow::Owned(reindented_line.clone());
11064                reindented_line.clear();
11065            }
11066        });
11067    }
11068
11069    pub fn convert_to_upper_case(
11070        &mut self,
11071        _: &ConvertToUpperCase,
11072        window: &mut Window,
11073        cx: &mut Context<Self>,
11074    ) {
11075        self.manipulate_text(window, cx, |text| text.to_uppercase())
11076    }
11077
11078    pub fn convert_to_lower_case(
11079        &mut self,
11080        _: &ConvertToLowerCase,
11081        window: &mut Window,
11082        cx: &mut Context<Self>,
11083    ) {
11084        self.manipulate_text(window, cx, |text| text.to_lowercase())
11085    }
11086
11087    pub fn convert_to_title_case(
11088        &mut self,
11089        _: &ConvertToTitleCase,
11090        window: &mut Window,
11091        cx: &mut Context<Self>,
11092    ) {
11093        self.manipulate_text(window, cx, |text| {
11094            text.split('\n')
11095                .map(|line| line.to_case(Case::Title))
11096                .join("\n")
11097        })
11098    }
11099
11100    pub fn convert_to_snake_case(
11101        &mut self,
11102        _: &ConvertToSnakeCase,
11103        window: &mut Window,
11104        cx: &mut Context<Self>,
11105    ) {
11106        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11107    }
11108
11109    pub fn convert_to_kebab_case(
11110        &mut self,
11111        _: &ConvertToKebabCase,
11112        window: &mut Window,
11113        cx: &mut Context<Self>,
11114    ) {
11115        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11116    }
11117
11118    pub fn convert_to_upper_camel_case(
11119        &mut self,
11120        _: &ConvertToUpperCamelCase,
11121        window: &mut Window,
11122        cx: &mut Context<Self>,
11123    ) {
11124        self.manipulate_text(window, cx, |text| {
11125            text.split('\n')
11126                .map(|line| line.to_case(Case::UpperCamel))
11127                .join("\n")
11128        })
11129    }
11130
11131    pub fn convert_to_lower_camel_case(
11132        &mut self,
11133        _: &ConvertToLowerCamelCase,
11134        window: &mut Window,
11135        cx: &mut Context<Self>,
11136    ) {
11137        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11138    }
11139
11140    pub fn convert_to_opposite_case(
11141        &mut self,
11142        _: &ConvertToOppositeCase,
11143        window: &mut Window,
11144        cx: &mut Context<Self>,
11145    ) {
11146        self.manipulate_text(window, cx, |text| {
11147            text.chars()
11148                .fold(String::with_capacity(text.len()), |mut t, c| {
11149                    if c.is_uppercase() {
11150                        t.extend(c.to_lowercase());
11151                    } else {
11152                        t.extend(c.to_uppercase());
11153                    }
11154                    t
11155                })
11156        })
11157    }
11158
11159    pub fn convert_to_sentence_case(
11160        &mut self,
11161        _: &ConvertToSentenceCase,
11162        window: &mut Window,
11163        cx: &mut Context<Self>,
11164    ) {
11165        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11166    }
11167
11168    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11169        self.manipulate_text(window, cx, |text| {
11170            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11171            if has_upper_case_characters {
11172                text.to_lowercase()
11173            } else {
11174                text.to_uppercase()
11175            }
11176        })
11177    }
11178
11179    pub fn convert_to_rot13(
11180        &mut self,
11181        _: &ConvertToRot13,
11182        window: &mut Window,
11183        cx: &mut Context<Self>,
11184    ) {
11185        self.manipulate_text(window, cx, |text| {
11186            text.chars()
11187                .map(|c| match c {
11188                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11189                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11190                    _ => c,
11191                })
11192                .collect()
11193        })
11194    }
11195
11196    pub fn convert_to_rot47(
11197        &mut self,
11198        _: &ConvertToRot47,
11199        window: &mut Window,
11200        cx: &mut Context<Self>,
11201    ) {
11202        self.manipulate_text(window, cx, |text| {
11203            text.chars()
11204                .map(|c| {
11205                    let code_point = c as u32;
11206                    if code_point >= 33 && code_point <= 126 {
11207                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11208                    }
11209                    c
11210                })
11211                .collect()
11212        })
11213    }
11214
11215    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11216    where
11217        Fn: FnMut(&str) -> String,
11218    {
11219        let buffer = self.buffer.read(cx).snapshot(cx);
11220
11221        let mut new_selections = Vec::new();
11222        let mut edits = Vec::new();
11223        let mut selection_adjustment = 0i32;
11224
11225        for selection in self.selections.all::<usize>(cx) {
11226            let selection_is_empty = selection.is_empty();
11227
11228            let (start, end) = if selection_is_empty {
11229                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11230                (word_range.start, word_range.end)
11231            } else {
11232                (selection.start, selection.end)
11233            };
11234
11235            let text = buffer.text_for_range(start..end).collect::<String>();
11236            let old_length = text.len() as i32;
11237            let text = callback(&text);
11238
11239            new_selections.push(Selection {
11240                start: (start as i32 - selection_adjustment) as usize,
11241                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11242                goal: SelectionGoal::None,
11243                ..selection
11244            });
11245
11246            selection_adjustment += old_length - text.len() as i32;
11247
11248            edits.push((start..end, text));
11249        }
11250
11251        self.transact(window, cx, |this, window, cx| {
11252            this.buffer.update(cx, |buffer, cx| {
11253                buffer.edit(edits, None, cx);
11254            });
11255
11256            this.change_selections(Default::default(), window, cx, |s| {
11257                s.select(new_selections);
11258            });
11259
11260            this.request_autoscroll(Autoscroll::fit(), cx);
11261        });
11262    }
11263
11264    pub fn move_selection_on_drop(
11265        &mut self,
11266        selection: &Selection<Anchor>,
11267        target: DisplayPoint,
11268        is_cut: bool,
11269        window: &mut Window,
11270        cx: &mut Context<Self>,
11271    ) {
11272        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11273        let buffer = &display_map.buffer_snapshot;
11274        let mut edits = Vec::new();
11275        let insert_point = display_map
11276            .clip_point(target, Bias::Left)
11277            .to_point(&display_map);
11278        let text = buffer
11279            .text_for_range(selection.start..selection.end)
11280            .collect::<String>();
11281        if is_cut {
11282            edits.push(((selection.start..selection.end), String::new()));
11283        }
11284        let insert_anchor = buffer.anchor_before(insert_point);
11285        edits.push(((insert_anchor..insert_anchor), text));
11286        let last_edit_start = insert_anchor.bias_left(buffer);
11287        let last_edit_end = insert_anchor.bias_right(buffer);
11288        self.transact(window, cx, |this, window, cx| {
11289            this.buffer.update(cx, |buffer, cx| {
11290                buffer.edit(edits, None, cx);
11291            });
11292            this.change_selections(Default::default(), window, cx, |s| {
11293                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11294            });
11295        });
11296    }
11297
11298    pub fn clear_selection_drag_state(&mut self) {
11299        self.selection_drag_state = SelectionDragState::None;
11300    }
11301
11302    pub fn duplicate(
11303        &mut self,
11304        upwards: bool,
11305        whole_lines: bool,
11306        window: &mut Window,
11307        cx: &mut Context<Self>,
11308    ) {
11309        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11310
11311        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11312        let buffer = &display_map.buffer_snapshot;
11313        let selections = self.selections.all::<Point>(cx);
11314
11315        let mut edits = Vec::new();
11316        let mut selections_iter = selections.iter().peekable();
11317        while let Some(selection) = selections_iter.next() {
11318            let mut rows = selection.spanned_rows(false, &display_map);
11319            // duplicate line-wise
11320            if whole_lines || selection.start == selection.end {
11321                // Avoid duplicating the same lines twice.
11322                while let Some(next_selection) = selections_iter.peek() {
11323                    let next_rows = next_selection.spanned_rows(false, &display_map);
11324                    if next_rows.start < rows.end {
11325                        rows.end = next_rows.end;
11326                        selections_iter.next().unwrap();
11327                    } else {
11328                        break;
11329                    }
11330                }
11331
11332                // Copy the text from the selected row region and splice it either at the start
11333                // or end of the region.
11334                let start = Point::new(rows.start.0, 0);
11335                let end = Point::new(
11336                    rows.end.previous_row().0,
11337                    buffer.line_len(rows.end.previous_row()),
11338                );
11339                let text = buffer
11340                    .text_for_range(start..end)
11341                    .chain(Some("\n"))
11342                    .collect::<String>();
11343                let insert_location = if upwards {
11344                    Point::new(rows.end.0, 0)
11345                } else {
11346                    start
11347                };
11348                edits.push((insert_location..insert_location, text));
11349            } else {
11350                // duplicate character-wise
11351                let start = selection.start;
11352                let end = selection.end;
11353                let text = buffer.text_for_range(start..end).collect::<String>();
11354                edits.push((selection.end..selection.end, text));
11355            }
11356        }
11357
11358        self.transact(window, cx, |this, _, cx| {
11359            this.buffer.update(cx, |buffer, cx| {
11360                buffer.edit(edits, None, cx);
11361            });
11362
11363            this.request_autoscroll(Autoscroll::fit(), cx);
11364        });
11365    }
11366
11367    pub fn duplicate_line_up(
11368        &mut self,
11369        _: &DuplicateLineUp,
11370        window: &mut Window,
11371        cx: &mut Context<Self>,
11372    ) {
11373        self.duplicate(true, true, window, cx);
11374    }
11375
11376    pub fn duplicate_line_down(
11377        &mut self,
11378        _: &DuplicateLineDown,
11379        window: &mut Window,
11380        cx: &mut Context<Self>,
11381    ) {
11382        self.duplicate(false, true, window, cx);
11383    }
11384
11385    pub fn duplicate_selection(
11386        &mut self,
11387        _: &DuplicateSelection,
11388        window: &mut Window,
11389        cx: &mut Context<Self>,
11390    ) {
11391        self.duplicate(false, false, window, cx);
11392    }
11393
11394    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11395        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11396        if self.mode.is_single_line() {
11397            cx.propagate();
11398            return;
11399        }
11400
11401        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11402        let buffer = self.buffer.read(cx).snapshot(cx);
11403
11404        let mut edits = Vec::new();
11405        let mut unfold_ranges = Vec::new();
11406        let mut refold_creases = Vec::new();
11407
11408        let selections = self.selections.all::<Point>(cx);
11409        let mut selections = selections.iter().peekable();
11410        let mut contiguous_row_selections = Vec::new();
11411        let mut new_selections = Vec::new();
11412
11413        while let Some(selection) = selections.next() {
11414            // Find all the selections that span a contiguous row range
11415            let (start_row, end_row) = consume_contiguous_rows(
11416                &mut contiguous_row_selections,
11417                selection,
11418                &display_map,
11419                &mut selections,
11420            );
11421
11422            // Move the text spanned by the row range to be before the line preceding the row range
11423            if start_row.0 > 0 {
11424                let range_to_move = Point::new(
11425                    start_row.previous_row().0,
11426                    buffer.line_len(start_row.previous_row()),
11427                )
11428                    ..Point::new(
11429                        end_row.previous_row().0,
11430                        buffer.line_len(end_row.previous_row()),
11431                    );
11432                let insertion_point = display_map
11433                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11434                    .0;
11435
11436                // Don't move lines across excerpts
11437                if buffer
11438                    .excerpt_containing(insertion_point..range_to_move.end)
11439                    .is_some()
11440                {
11441                    let text = buffer
11442                        .text_for_range(range_to_move.clone())
11443                        .flat_map(|s| s.chars())
11444                        .skip(1)
11445                        .chain(['\n'])
11446                        .collect::<String>();
11447
11448                    edits.push((
11449                        buffer.anchor_after(range_to_move.start)
11450                            ..buffer.anchor_before(range_to_move.end),
11451                        String::new(),
11452                    ));
11453                    let insertion_anchor = buffer.anchor_after(insertion_point);
11454                    edits.push((insertion_anchor..insertion_anchor, text));
11455
11456                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11457
11458                    // Move selections up
11459                    new_selections.extend(contiguous_row_selections.drain(..).map(
11460                        |mut selection| {
11461                            selection.start.row -= row_delta;
11462                            selection.end.row -= row_delta;
11463                            selection
11464                        },
11465                    ));
11466
11467                    // Move folds up
11468                    unfold_ranges.push(range_to_move.clone());
11469                    for fold in display_map.folds_in_range(
11470                        buffer.anchor_before(range_to_move.start)
11471                            ..buffer.anchor_after(range_to_move.end),
11472                    ) {
11473                        let mut start = fold.range.start.to_point(&buffer);
11474                        let mut end = fold.range.end.to_point(&buffer);
11475                        start.row -= row_delta;
11476                        end.row -= row_delta;
11477                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11478                    }
11479                }
11480            }
11481
11482            // If we didn't move line(s), preserve the existing selections
11483            new_selections.append(&mut contiguous_row_selections);
11484        }
11485
11486        self.transact(window, cx, |this, window, cx| {
11487            this.unfold_ranges(&unfold_ranges, true, true, cx);
11488            this.buffer.update(cx, |buffer, cx| {
11489                for (range, text) in edits {
11490                    buffer.edit([(range, text)], None, cx);
11491                }
11492            });
11493            this.fold_creases(refold_creases, true, window, cx);
11494            this.change_selections(Default::default(), window, cx, |s| {
11495                s.select(new_selections);
11496            })
11497        });
11498    }
11499
11500    pub fn move_line_down(
11501        &mut self,
11502        _: &MoveLineDown,
11503        window: &mut Window,
11504        cx: &mut Context<Self>,
11505    ) {
11506        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11507        if self.mode.is_single_line() {
11508            cx.propagate();
11509            return;
11510        }
11511
11512        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11513        let buffer = self.buffer.read(cx).snapshot(cx);
11514
11515        let mut edits = Vec::new();
11516        let mut unfold_ranges = Vec::new();
11517        let mut refold_creases = Vec::new();
11518
11519        let selections = self.selections.all::<Point>(cx);
11520        let mut selections = selections.iter().peekable();
11521        let mut contiguous_row_selections = Vec::new();
11522        let mut new_selections = Vec::new();
11523
11524        while let Some(selection) = selections.next() {
11525            // Find all the selections that span a contiguous row range
11526            let (start_row, end_row) = consume_contiguous_rows(
11527                &mut contiguous_row_selections,
11528                selection,
11529                &display_map,
11530                &mut selections,
11531            );
11532
11533            // Move the text spanned by the row range to be after the last line of the row range
11534            if end_row.0 <= buffer.max_point().row {
11535                let range_to_move =
11536                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11537                let insertion_point = display_map
11538                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11539                    .0;
11540
11541                // Don't move lines across excerpt boundaries
11542                if buffer
11543                    .excerpt_containing(range_to_move.start..insertion_point)
11544                    .is_some()
11545                {
11546                    let mut text = String::from("\n");
11547                    text.extend(buffer.text_for_range(range_to_move.clone()));
11548                    text.pop(); // Drop trailing newline
11549                    edits.push((
11550                        buffer.anchor_after(range_to_move.start)
11551                            ..buffer.anchor_before(range_to_move.end),
11552                        String::new(),
11553                    ));
11554                    let insertion_anchor = buffer.anchor_after(insertion_point);
11555                    edits.push((insertion_anchor..insertion_anchor, text));
11556
11557                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11558
11559                    // Move selections down
11560                    new_selections.extend(contiguous_row_selections.drain(..).map(
11561                        |mut selection| {
11562                            selection.start.row += row_delta;
11563                            selection.end.row += row_delta;
11564                            selection
11565                        },
11566                    ));
11567
11568                    // Move folds down
11569                    unfold_ranges.push(range_to_move.clone());
11570                    for fold in display_map.folds_in_range(
11571                        buffer.anchor_before(range_to_move.start)
11572                            ..buffer.anchor_after(range_to_move.end),
11573                    ) {
11574                        let mut start = fold.range.start.to_point(&buffer);
11575                        let mut end = fold.range.end.to_point(&buffer);
11576                        start.row += row_delta;
11577                        end.row += row_delta;
11578                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11579                    }
11580                }
11581            }
11582
11583            // If we didn't move line(s), preserve the existing selections
11584            new_selections.append(&mut contiguous_row_selections);
11585        }
11586
11587        self.transact(window, cx, |this, window, cx| {
11588            this.unfold_ranges(&unfold_ranges, true, true, cx);
11589            this.buffer.update(cx, |buffer, cx| {
11590                for (range, text) in edits {
11591                    buffer.edit([(range, text)], None, cx);
11592                }
11593            });
11594            this.fold_creases(refold_creases, true, window, cx);
11595            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11596        });
11597    }
11598
11599    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11600        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11601        let text_layout_details = &self.text_layout_details(window);
11602        self.transact(window, cx, |this, window, cx| {
11603            let edits = this.change_selections(Default::default(), window, cx, |s| {
11604                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11605                s.move_with(|display_map, selection| {
11606                    if !selection.is_empty() {
11607                        return;
11608                    }
11609
11610                    let mut head = selection.head();
11611                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11612                    if head.column() == display_map.line_len(head.row()) {
11613                        transpose_offset = display_map
11614                            .buffer_snapshot
11615                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11616                    }
11617
11618                    if transpose_offset == 0 {
11619                        return;
11620                    }
11621
11622                    *head.column_mut() += 1;
11623                    head = display_map.clip_point(head, Bias::Right);
11624                    let goal = SelectionGoal::HorizontalPosition(
11625                        display_map
11626                            .x_for_display_point(head, text_layout_details)
11627                            .into(),
11628                    );
11629                    selection.collapse_to(head, goal);
11630
11631                    let transpose_start = display_map
11632                        .buffer_snapshot
11633                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11634                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11635                        let transpose_end = display_map
11636                            .buffer_snapshot
11637                            .clip_offset(transpose_offset + 1, Bias::Right);
11638                        if let Some(ch) =
11639                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11640                        {
11641                            edits.push((transpose_start..transpose_offset, String::new()));
11642                            edits.push((transpose_end..transpose_end, ch.to_string()));
11643                        }
11644                    }
11645                });
11646                edits
11647            });
11648            this.buffer
11649                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11650            let selections = this.selections.all::<usize>(cx);
11651            this.change_selections(Default::default(), window, cx, |s| {
11652                s.select(selections);
11653            });
11654        });
11655    }
11656
11657    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11658        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11659        if self.mode.is_single_line() {
11660            cx.propagate();
11661            return;
11662        }
11663
11664        self.rewrap_impl(RewrapOptions::default(), cx)
11665    }
11666
11667    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11668        let buffer = self.buffer.read(cx).snapshot(cx);
11669        let selections = self.selections.all::<Point>(cx);
11670
11671        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11672        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11673            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11674                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11675                .peekable();
11676
11677            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11678                row
11679            } else {
11680                return Vec::new();
11681            };
11682
11683            let language_settings = buffer.language_settings_at(selection.head(), cx);
11684            let language_scope = buffer.language_scope_at(selection.head());
11685
11686            let indent_and_prefix_for_row =
11687                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11688                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11689                    let (comment_prefix, rewrap_prefix) =
11690                        if let Some(language_scope) = &language_scope {
11691                            let indent_end = Point::new(row, indent.len);
11692                            let comment_prefix = language_scope
11693                                .line_comment_prefixes()
11694                                .iter()
11695                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11696                                .map(|prefix| prefix.to_string());
11697                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11698                            let line_text_after_indent = buffer
11699                                .text_for_range(indent_end..line_end)
11700                                .collect::<String>();
11701                            let rewrap_prefix = language_scope
11702                                .rewrap_prefixes()
11703                                .iter()
11704                                .find_map(|prefix_regex| {
11705                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11706                                        if mat.start() == 0 {
11707                                            Some(mat.as_str().to_string())
11708                                        } else {
11709                                            None
11710                                        }
11711                                    })
11712                                })
11713                                .flatten();
11714                            (comment_prefix, rewrap_prefix)
11715                        } else {
11716                            (None, None)
11717                        };
11718                    (indent, comment_prefix, rewrap_prefix)
11719                };
11720
11721            let mut ranges = Vec::new();
11722            let from_empty_selection = selection.is_empty();
11723
11724            let mut current_range_start = first_row;
11725            let mut prev_row = first_row;
11726            let (
11727                mut current_range_indent,
11728                mut current_range_comment_prefix,
11729                mut current_range_rewrap_prefix,
11730            ) = indent_and_prefix_for_row(first_row);
11731
11732            for row in non_blank_rows_iter.skip(1) {
11733                let has_paragraph_break = row > prev_row + 1;
11734
11735                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11736                    indent_and_prefix_for_row(row);
11737
11738                let has_indent_change = row_indent != current_range_indent;
11739                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11740
11741                let has_boundary_change = has_comment_change
11742                    || row_rewrap_prefix.is_some()
11743                    || (has_indent_change && current_range_comment_prefix.is_some());
11744
11745                if has_paragraph_break || has_boundary_change {
11746                    ranges.push((
11747                        language_settings.clone(),
11748                        Point::new(current_range_start, 0)
11749                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11750                        current_range_indent,
11751                        current_range_comment_prefix.clone(),
11752                        current_range_rewrap_prefix.clone(),
11753                        from_empty_selection,
11754                    ));
11755                    current_range_start = row;
11756                    current_range_indent = row_indent;
11757                    current_range_comment_prefix = row_comment_prefix;
11758                    current_range_rewrap_prefix = row_rewrap_prefix;
11759                }
11760                prev_row = row;
11761            }
11762
11763            ranges.push((
11764                language_settings.clone(),
11765                Point::new(current_range_start, 0)
11766                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11767                current_range_indent,
11768                current_range_comment_prefix,
11769                current_range_rewrap_prefix,
11770                from_empty_selection,
11771            ));
11772
11773            ranges
11774        });
11775
11776        let mut edits = Vec::new();
11777        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11778
11779        for (
11780            language_settings,
11781            wrap_range,
11782            indent_size,
11783            comment_prefix,
11784            rewrap_prefix,
11785            from_empty_selection,
11786        ) in wrap_ranges
11787        {
11788            let mut start_row = wrap_range.start.row;
11789            let mut end_row = wrap_range.end.row;
11790
11791            // Skip selections that overlap with a range that has already been rewrapped.
11792            let selection_range = start_row..end_row;
11793            if rewrapped_row_ranges
11794                .iter()
11795                .any(|range| range.overlaps(&selection_range))
11796            {
11797                continue;
11798            }
11799
11800            let tab_size = language_settings.tab_size;
11801
11802            let indent_prefix = indent_size.chars().collect::<String>();
11803            let mut line_prefix = indent_prefix.clone();
11804            let mut inside_comment = false;
11805            if let Some(prefix) = &comment_prefix {
11806                line_prefix.push_str(prefix);
11807                inside_comment = true;
11808            }
11809            if let Some(prefix) = &rewrap_prefix {
11810                line_prefix.push_str(prefix);
11811            }
11812
11813            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11814                RewrapBehavior::InComments => inside_comment,
11815                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11816                RewrapBehavior::Anywhere => true,
11817            };
11818
11819            let should_rewrap = options.override_language_settings
11820                || allow_rewrap_based_on_language
11821                || self.hard_wrap.is_some();
11822            if !should_rewrap {
11823                continue;
11824            }
11825
11826            if from_empty_selection {
11827                'expand_upwards: while start_row > 0 {
11828                    let prev_row = start_row - 1;
11829                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11830                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11831                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11832                    {
11833                        start_row = prev_row;
11834                    } else {
11835                        break 'expand_upwards;
11836                    }
11837                }
11838
11839                'expand_downwards: while end_row < buffer.max_point().row {
11840                    let next_row = end_row + 1;
11841                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11842                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11843                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11844                    {
11845                        end_row = next_row;
11846                    } else {
11847                        break 'expand_downwards;
11848                    }
11849                }
11850            }
11851
11852            let start = Point::new(start_row, 0);
11853            let start_offset = start.to_offset(&buffer);
11854            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11855            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11856            let Some(lines_without_prefixes) = selection_text
11857                .lines()
11858                .enumerate()
11859                .map(|(ix, line)| {
11860                    let line_trimmed = line.trim_start();
11861                    if rewrap_prefix.is_some() && ix > 0 {
11862                        Ok(line_trimmed)
11863                    } else {
11864                        line_trimmed
11865                            .strip_prefix(&line_prefix.trim_start())
11866                            .with_context(|| {
11867                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11868                            })
11869                    }
11870                })
11871                .collect::<Result<Vec<_>, _>>()
11872                .log_err()
11873            else {
11874                continue;
11875            };
11876
11877            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11878                buffer
11879                    .language_settings_at(Point::new(start_row, 0), cx)
11880                    .preferred_line_length as usize
11881            });
11882
11883            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11884                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11885            } else {
11886                line_prefix.clone()
11887            };
11888
11889            let wrapped_text = wrap_with_prefix(
11890                line_prefix,
11891                subsequent_lines_prefix,
11892                lines_without_prefixes.join("\n"),
11893                wrap_column,
11894                tab_size,
11895                options.preserve_existing_whitespace,
11896            );
11897
11898            // TODO: should always use char-based diff while still supporting cursor behavior that
11899            // matches vim.
11900            let mut diff_options = DiffOptions::default();
11901            if options.override_language_settings {
11902                diff_options.max_word_diff_len = 0;
11903                diff_options.max_word_diff_line_count = 0;
11904            } else {
11905                diff_options.max_word_diff_len = usize::MAX;
11906                diff_options.max_word_diff_line_count = usize::MAX;
11907            }
11908
11909            for (old_range, new_text) in
11910                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11911            {
11912                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11913                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11914                edits.push((edit_start..edit_end, new_text));
11915            }
11916
11917            rewrapped_row_ranges.push(start_row..=end_row);
11918        }
11919
11920        self.buffer
11921            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11922    }
11923
11924    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11925        let mut text = String::new();
11926        let buffer = self.buffer.read(cx).snapshot(cx);
11927        let mut selections = self.selections.all::<Point>(cx);
11928        let mut clipboard_selections = Vec::with_capacity(selections.len());
11929        {
11930            let max_point = buffer.max_point();
11931            let mut is_first = true;
11932            for selection in &mut selections {
11933                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11934                if is_entire_line {
11935                    selection.start = Point::new(selection.start.row, 0);
11936                    if !selection.is_empty() && selection.end.column == 0 {
11937                        selection.end = cmp::min(max_point, selection.end);
11938                    } else {
11939                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11940                    }
11941                    selection.goal = SelectionGoal::None;
11942                }
11943                if is_first {
11944                    is_first = false;
11945                } else {
11946                    text += "\n";
11947                }
11948                let mut len = 0;
11949                for chunk in buffer.text_for_range(selection.start..selection.end) {
11950                    text.push_str(chunk);
11951                    len += chunk.len();
11952                }
11953                clipboard_selections.push(ClipboardSelection {
11954                    len,
11955                    is_entire_line,
11956                    first_line_indent: buffer
11957                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11958                        .len,
11959                });
11960            }
11961        }
11962
11963        self.transact(window, cx, |this, window, cx| {
11964            this.change_selections(Default::default(), window, cx, |s| {
11965                s.select(selections);
11966            });
11967            this.insert("", window, cx);
11968        });
11969        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11970    }
11971
11972    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11973        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11974        let item = self.cut_common(window, cx);
11975        cx.write_to_clipboard(item);
11976    }
11977
11978    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11979        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11980        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11981            s.move_with(|snapshot, sel| {
11982                if sel.is_empty() {
11983                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11984                }
11985            });
11986        });
11987        let item = self.cut_common(window, cx);
11988        cx.set_global(KillRing(item))
11989    }
11990
11991    pub fn kill_ring_yank(
11992        &mut self,
11993        _: &KillRingYank,
11994        window: &mut Window,
11995        cx: &mut Context<Self>,
11996    ) {
11997        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11998        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11999            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12000                (kill_ring.text().to_string(), kill_ring.metadata_json())
12001            } else {
12002                return;
12003            }
12004        } else {
12005            return;
12006        };
12007        self.do_paste(&text, metadata, false, window, cx);
12008    }
12009
12010    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12011        self.do_copy(true, cx);
12012    }
12013
12014    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12015        self.do_copy(false, cx);
12016    }
12017
12018    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12019        let selections = self.selections.all::<Point>(cx);
12020        let buffer = self.buffer.read(cx).read(cx);
12021        let mut text = String::new();
12022
12023        let mut clipboard_selections = Vec::with_capacity(selections.len());
12024        {
12025            let max_point = buffer.max_point();
12026            let mut is_first = true;
12027            for selection in &selections {
12028                let mut start = selection.start;
12029                let mut end = selection.end;
12030                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12031                if is_entire_line {
12032                    start = Point::new(start.row, 0);
12033                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12034                }
12035
12036                let mut trimmed_selections = Vec::new();
12037                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12038                    let row = MultiBufferRow(start.row);
12039                    let first_indent = buffer.indent_size_for_line(row);
12040                    if first_indent.len == 0 || start.column > first_indent.len {
12041                        trimmed_selections.push(start..end);
12042                    } else {
12043                        trimmed_selections.push(
12044                            Point::new(row.0, first_indent.len)
12045                                ..Point::new(row.0, buffer.line_len(row)),
12046                        );
12047                        for row in start.row + 1..=end.row {
12048                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12049                            if row == end.row {
12050                                line_len = end.column;
12051                            }
12052                            if line_len == 0 {
12053                                trimmed_selections
12054                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12055                                continue;
12056                            }
12057                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12058                            if row_indent_size.len >= first_indent.len {
12059                                trimmed_selections.push(
12060                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12061                                );
12062                            } else {
12063                                trimmed_selections.clear();
12064                                trimmed_selections.push(start..end);
12065                                break;
12066                            }
12067                        }
12068                    }
12069                } else {
12070                    trimmed_selections.push(start..end);
12071                }
12072
12073                for trimmed_range in trimmed_selections {
12074                    if is_first {
12075                        is_first = false;
12076                    } else {
12077                        text += "\n";
12078                    }
12079                    let mut len = 0;
12080                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12081                        text.push_str(chunk);
12082                        len += chunk.len();
12083                    }
12084                    clipboard_selections.push(ClipboardSelection {
12085                        len,
12086                        is_entire_line,
12087                        first_line_indent: buffer
12088                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12089                            .len,
12090                    });
12091                }
12092            }
12093        }
12094
12095        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12096            text,
12097            clipboard_selections,
12098        ));
12099    }
12100
12101    pub fn do_paste(
12102        &mut self,
12103        text: &String,
12104        clipboard_selections: Option<Vec<ClipboardSelection>>,
12105        handle_entire_lines: bool,
12106        window: &mut Window,
12107        cx: &mut Context<Self>,
12108    ) {
12109        if self.read_only(cx) {
12110            return;
12111        }
12112
12113        let clipboard_text = Cow::Borrowed(text);
12114
12115        self.transact(window, cx, |this, window, cx| {
12116            if let Some(mut clipboard_selections) = clipboard_selections {
12117                let old_selections = this.selections.all::<usize>(cx);
12118                let all_selections_were_entire_line =
12119                    clipboard_selections.iter().all(|s| s.is_entire_line);
12120                let first_selection_indent_column =
12121                    clipboard_selections.first().map(|s| s.first_line_indent);
12122                if clipboard_selections.len() != old_selections.len() {
12123                    clipboard_selections.drain(..);
12124                }
12125                let cursor_offset = this.selections.last::<usize>(cx).head();
12126                let mut auto_indent_on_paste = true;
12127
12128                this.buffer.update(cx, |buffer, cx| {
12129                    let snapshot = buffer.read(cx);
12130                    auto_indent_on_paste = snapshot
12131                        .language_settings_at(cursor_offset, cx)
12132                        .auto_indent_on_paste;
12133
12134                    let mut start_offset = 0;
12135                    let mut edits = Vec::new();
12136                    let mut original_indent_columns = Vec::new();
12137                    for (ix, selection) in old_selections.iter().enumerate() {
12138                        let to_insert;
12139                        let entire_line;
12140                        let original_indent_column;
12141                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12142                            let end_offset = start_offset + clipboard_selection.len;
12143                            to_insert = &clipboard_text[start_offset..end_offset];
12144                            entire_line = clipboard_selection.is_entire_line;
12145                            start_offset = end_offset + 1;
12146                            original_indent_column = Some(clipboard_selection.first_line_indent);
12147                        } else {
12148                            to_insert = clipboard_text.as_str();
12149                            entire_line = all_selections_were_entire_line;
12150                            original_indent_column = first_selection_indent_column
12151                        }
12152
12153                        // If the corresponding selection was empty when this slice of the
12154                        // clipboard text was written, then the entire line containing the
12155                        // selection was copied. If this selection is also currently empty,
12156                        // then paste the line before the current line of the buffer.
12157                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12158                            let column = selection.start.to_point(&snapshot).column as usize;
12159                            let line_start = selection.start - column;
12160                            line_start..line_start
12161                        } else {
12162                            selection.range()
12163                        };
12164
12165                        edits.push((range, to_insert));
12166                        original_indent_columns.push(original_indent_column);
12167                    }
12168                    drop(snapshot);
12169
12170                    buffer.edit(
12171                        edits,
12172                        if auto_indent_on_paste {
12173                            Some(AutoindentMode::Block {
12174                                original_indent_columns,
12175                            })
12176                        } else {
12177                            None
12178                        },
12179                        cx,
12180                    );
12181                });
12182
12183                let selections = this.selections.all::<usize>(cx);
12184                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12185            } else {
12186                this.insert(&clipboard_text, window, cx);
12187            }
12188        });
12189    }
12190
12191    pub fn diff_clipboard_with_selection(
12192        &mut self,
12193        _: &DiffClipboardWithSelection,
12194        window: &mut Window,
12195        cx: &mut Context<Self>,
12196    ) {
12197        let selections = self.selections.all::<usize>(cx);
12198
12199        if selections.is_empty() {
12200            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12201            return;
12202        };
12203
12204        let clipboard_text = match cx.read_from_clipboard() {
12205            Some(item) => match item.entries().first() {
12206                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12207                _ => None,
12208            },
12209            None => None,
12210        };
12211
12212        let Some(clipboard_text) = clipboard_text else {
12213            log::warn!("Clipboard doesn't contain text.");
12214            return;
12215        };
12216
12217        window.dispatch_action(
12218            Box::new(DiffClipboardWithSelectionData {
12219                clipboard_text,
12220                editor: cx.entity(),
12221            }),
12222            cx,
12223        );
12224    }
12225
12226    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12227        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12228        if let Some(item) = cx.read_from_clipboard() {
12229            let entries = item.entries();
12230
12231            match entries.first() {
12232                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12233                // of all the pasted entries.
12234                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12235                    .do_paste(
12236                        clipboard_string.text(),
12237                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12238                        true,
12239                        window,
12240                        cx,
12241                    ),
12242                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12243            }
12244        }
12245    }
12246
12247    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12248        if self.read_only(cx) {
12249            return;
12250        }
12251
12252        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12253
12254        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12255            if let Some((selections, _)) =
12256                self.selection_history.transaction(transaction_id).cloned()
12257            {
12258                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12259                    s.select_anchors(selections.to_vec());
12260                });
12261            } else {
12262                log::error!(
12263                    "No entry in selection_history found for undo. \
12264                     This may correspond to a bug where undo does not update the selection. \
12265                     If this is occurring, please add details to \
12266                     https://github.com/zed-industries/zed/issues/22692"
12267                );
12268            }
12269            self.request_autoscroll(Autoscroll::fit(), cx);
12270            self.unmark_text(window, cx);
12271            self.refresh_inline_completion(true, false, window, cx);
12272            cx.emit(EditorEvent::Edited { transaction_id });
12273            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12274        }
12275    }
12276
12277    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12278        if self.read_only(cx) {
12279            return;
12280        }
12281
12282        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12283
12284        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12285            if let Some((_, Some(selections))) =
12286                self.selection_history.transaction(transaction_id).cloned()
12287            {
12288                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12289                    s.select_anchors(selections.to_vec());
12290                });
12291            } else {
12292                log::error!(
12293                    "No entry in selection_history found for redo. \
12294                     This may correspond to a bug where undo does not update the selection. \
12295                     If this is occurring, please add details to \
12296                     https://github.com/zed-industries/zed/issues/22692"
12297                );
12298            }
12299            self.request_autoscroll(Autoscroll::fit(), cx);
12300            self.unmark_text(window, cx);
12301            self.refresh_inline_completion(true, false, window, cx);
12302            cx.emit(EditorEvent::Edited { transaction_id });
12303        }
12304    }
12305
12306    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12307        self.buffer
12308            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12309    }
12310
12311    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12312        self.buffer
12313            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12314    }
12315
12316    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12317        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12318        self.change_selections(Default::default(), window, cx, |s| {
12319            s.move_with(|map, selection| {
12320                let cursor = if selection.is_empty() {
12321                    movement::left(map, selection.start)
12322                } else {
12323                    selection.start
12324                };
12325                selection.collapse_to(cursor, SelectionGoal::None);
12326            });
12327        })
12328    }
12329
12330    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12331        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12332        self.change_selections(Default::default(), window, cx, |s| {
12333            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12334        })
12335    }
12336
12337    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12338        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12339        self.change_selections(Default::default(), window, cx, |s| {
12340            s.move_with(|map, selection| {
12341                let cursor = if selection.is_empty() {
12342                    movement::right(map, selection.end)
12343                } else {
12344                    selection.end
12345                };
12346                selection.collapse_to(cursor, SelectionGoal::None)
12347            });
12348        })
12349    }
12350
12351    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12352        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12353        self.change_selections(Default::default(), window, cx, |s| {
12354            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12355        })
12356    }
12357
12358    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12359        if self.take_rename(true, window, cx).is_some() {
12360            return;
12361        }
12362
12363        if self.mode.is_single_line() {
12364            cx.propagate();
12365            return;
12366        }
12367
12368        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12369
12370        let text_layout_details = &self.text_layout_details(window);
12371        let selection_count = self.selections.count();
12372        let first_selection = self.selections.first_anchor();
12373
12374        self.change_selections(Default::default(), window, cx, |s| {
12375            s.move_with(|map, selection| {
12376                if !selection.is_empty() {
12377                    selection.goal = SelectionGoal::None;
12378                }
12379                let (cursor, goal) = movement::up(
12380                    map,
12381                    selection.start,
12382                    selection.goal,
12383                    false,
12384                    text_layout_details,
12385                );
12386                selection.collapse_to(cursor, goal);
12387            });
12388        });
12389
12390        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12391        {
12392            cx.propagate();
12393        }
12394    }
12395
12396    pub fn move_up_by_lines(
12397        &mut self,
12398        action: &MoveUpByLines,
12399        window: &mut Window,
12400        cx: &mut Context<Self>,
12401    ) {
12402        if self.take_rename(true, window, cx).is_some() {
12403            return;
12404        }
12405
12406        if self.mode.is_single_line() {
12407            cx.propagate();
12408            return;
12409        }
12410
12411        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12412
12413        let text_layout_details = &self.text_layout_details(window);
12414
12415        self.change_selections(Default::default(), window, cx, |s| {
12416            s.move_with(|map, selection| {
12417                if !selection.is_empty() {
12418                    selection.goal = SelectionGoal::None;
12419                }
12420                let (cursor, goal) = movement::up_by_rows(
12421                    map,
12422                    selection.start,
12423                    action.lines,
12424                    selection.goal,
12425                    false,
12426                    text_layout_details,
12427                );
12428                selection.collapse_to(cursor, goal);
12429            });
12430        })
12431    }
12432
12433    pub fn move_down_by_lines(
12434        &mut self,
12435        action: &MoveDownByLines,
12436        window: &mut Window,
12437        cx: &mut Context<Self>,
12438    ) {
12439        if self.take_rename(true, window, cx).is_some() {
12440            return;
12441        }
12442
12443        if self.mode.is_single_line() {
12444            cx.propagate();
12445            return;
12446        }
12447
12448        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12449
12450        let text_layout_details = &self.text_layout_details(window);
12451
12452        self.change_selections(Default::default(), window, cx, |s| {
12453            s.move_with(|map, selection| {
12454                if !selection.is_empty() {
12455                    selection.goal = SelectionGoal::None;
12456                }
12457                let (cursor, goal) = movement::down_by_rows(
12458                    map,
12459                    selection.start,
12460                    action.lines,
12461                    selection.goal,
12462                    false,
12463                    text_layout_details,
12464                );
12465                selection.collapse_to(cursor, goal);
12466            });
12467        })
12468    }
12469
12470    pub fn select_down_by_lines(
12471        &mut self,
12472        action: &SelectDownByLines,
12473        window: &mut Window,
12474        cx: &mut Context<Self>,
12475    ) {
12476        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12477        let text_layout_details = &self.text_layout_details(window);
12478        self.change_selections(Default::default(), window, cx, |s| {
12479            s.move_heads_with(|map, head, goal| {
12480                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12481            })
12482        })
12483    }
12484
12485    pub fn select_up_by_lines(
12486        &mut self,
12487        action: &SelectUpByLines,
12488        window: &mut Window,
12489        cx: &mut Context<Self>,
12490    ) {
12491        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12492        let text_layout_details = &self.text_layout_details(window);
12493        self.change_selections(Default::default(), window, cx, |s| {
12494            s.move_heads_with(|map, head, goal| {
12495                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12496            })
12497        })
12498    }
12499
12500    pub fn select_page_up(
12501        &mut self,
12502        _: &SelectPageUp,
12503        window: &mut Window,
12504        cx: &mut Context<Self>,
12505    ) {
12506        let Some(row_count) = self.visible_row_count() else {
12507            return;
12508        };
12509
12510        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12511
12512        let text_layout_details = &self.text_layout_details(window);
12513
12514        self.change_selections(Default::default(), window, cx, |s| {
12515            s.move_heads_with(|map, head, goal| {
12516                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12517            })
12518        })
12519    }
12520
12521    pub fn move_page_up(
12522        &mut self,
12523        action: &MovePageUp,
12524        window: &mut Window,
12525        cx: &mut Context<Self>,
12526    ) {
12527        if self.take_rename(true, window, cx).is_some() {
12528            return;
12529        }
12530
12531        if self
12532            .context_menu
12533            .borrow_mut()
12534            .as_mut()
12535            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12536            .unwrap_or(false)
12537        {
12538            return;
12539        }
12540
12541        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12542            cx.propagate();
12543            return;
12544        }
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 effects = if action.center_cursor {
12553            SelectionEffects::scroll(Autoscroll::center())
12554        } else {
12555            SelectionEffects::default()
12556        };
12557
12558        let text_layout_details = &self.text_layout_details(window);
12559
12560        self.change_selections(effects, window, cx, |s| {
12561            s.move_with(|map, selection| {
12562                if !selection.is_empty() {
12563                    selection.goal = SelectionGoal::None;
12564                }
12565                let (cursor, goal) = movement::up_by_rows(
12566                    map,
12567                    selection.end,
12568                    row_count,
12569                    selection.goal,
12570                    false,
12571                    text_layout_details,
12572                );
12573                selection.collapse_to(cursor, goal);
12574            });
12575        });
12576    }
12577
12578    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12579        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12580        let text_layout_details = &self.text_layout_details(window);
12581        self.change_selections(Default::default(), window, cx, |s| {
12582            s.move_heads_with(|map, head, goal| {
12583                movement::up(map, head, goal, false, text_layout_details)
12584            })
12585        })
12586    }
12587
12588    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12589        self.take_rename(true, window, cx);
12590
12591        if self.mode.is_single_line() {
12592            cx.propagate();
12593            return;
12594        }
12595
12596        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12597
12598        let text_layout_details = &self.text_layout_details(window);
12599        let selection_count = self.selections.count();
12600        let first_selection = self.selections.first_anchor();
12601
12602        self.change_selections(Default::default(), window, cx, |s| {
12603            s.move_with(|map, selection| {
12604                if !selection.is_empty() {
12605                    selection.goal = SelectionGoal::None;
12606                }
12607                let (cursor, goal) = movement::down(
12608                    map,
12609                    selection.end,
12610                    selection.goal,
12611                    false,
12612                    text_layout_details,
12613                );
12614                selection.collapse_to(cursor, goal);
12615            });
12616        });
12617
12618        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12619        {
12620            cx.propagate();
12621        }
12622    }
12623
12624    pub fn select_page_down(
12625        &mut self,
12626        _: &SelectPageDown,
12627        window: &mut Window,
12628        cx: &mut Context<Self>,
12629    ) {
12630        let Some(row_count) = self.visible_row_count() else {
12631            return;
12632        };
12633
12634        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12635
12636        let text_layout_details = &self.text_layout_details(window);
12637
12638        self.change_selections(Default::default(), window, cx, |s| {
12639            s.move_heads_with(|map, head, goal| {
12640                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12641            })
12642        })
12643    }
12644
12645    pub fn move_page_down(
12646        &mut self,
12647        action: &MovePageDown,
12648        window: &mut Window,
12649        cx: &mut Context<Self>,
12650    ) {
12651        if self.take_rename(true, window, cx).is_some() {
12652            return;
12653        }
12654
12655        if self
12656            .context_menu
12657            .borrow_mut()
12658            .as_mut()
12659            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12660            .unwrap_or(false)
12661        {
12662            return;
12663        }
12664
12665        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12666            cx.propagate();
12667            return;
12668        }
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 effects = if action.center_cursor {
12677            SelectionEffects::scroll(Autoscroll::center())
12678        } else {
12679            SelectionEffects::default()
12680        };
12681
12682        let text_layout_details = &self.text_layout_details(window);
12683        self.change_selections(effects, window, cx, |s| {
12684            s.move_with(|map, selection| {
12685                if !selection.is_empty() {
12686                    selection.goal = SelectionGoal::None;
12687                }
12688                let (cursor, goal) = movement::down_by_rows(
12689                    map,
12690                    selection.end,
12691                    row_count,
12692                    selection.goal,
12693                    false,
12694                    text_layout_details,
12695                );
12696                selection.collapse_to(cursor, goal);
12697            });
12698        });
12699    }
12700
12701    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12702        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12703        let text_layout_details = &self.text_layout_details(window);
12704        self.change_selections(Default::default(), window, cx, |s| {
12705            s.move_heads_with(|map, head, goal| {
12706                movement::down(map, head, goal, false, text_layout_details)
12707            })
12708        });
12709    }
12710
12711    pub fn context_menu_first(
12712        &mut self,
12713        _: &ContextMenuFirst,
12714        window: &mut Window,
12715        cx: &mut Context<Self>,
12716    ) {
12717        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12718            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12719        }
12720    }
12721
12722    pub fn context_menu_prev(
12723        &mut self,
12724        _: &ContextMenuPrevious,
12725        window: &mut Window,
12726        cx: &mut Context<Self>,
12727    ) {
12728        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12729            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12730        }
12731    }
12732
12733    pub fn context_menu_next(
12734        &mut self,
12735        _: &ContextMenuNext,
12736        window: &mut Window,
12737        cx: &mut Context<Self>,
12738    ) {
12739        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12740            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12741        }
12742    }
12743
12744    pub fn context_menu_last(
12745        &mut self,
12746        _: &ContextMenuLast,
12747        window: &mut Window,
12748        cx: &mut Context<Self>,
12749    ) {
12750        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12751            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12752        }
12753    }
12754
12755    pub fn signature_help_prev(
12756        &mut self,
12757        _: &SignatureHelpPrevious,
12758        _: &mut Window,
12759        cx: &mut Context<Self>,
12760    ) {
12761        if let Some(popover) = self.signature_help_state.popover_mut() {
12762            if popover.current_signature == 0 {
12763                popover.current_signature = popover.signatures.len() - 1;
12764            } else {
12765                popover.current_signature -= 1;
12766            }
12767            cx.notify();
12768        }
12769    }
12770
12771    pub fn signature_help_next(
12772        &mut self,
12773        _: &SignatureHelpNext,
12774        _: &mut Window,
12775        cx: &mut Context<Self>,
12776    ) {
12777        if let Some(popover) = self.signature_help_state.popover_mut() {
12778            if popover.current_signature + 1 == popover.signatures.len() {
12779                popover.current_signature = 0;
12780            } else {
12781                popover.current_signature += 1;
12782            }
12783            cx.notify();
12784        }
12785    }
12786
12787    pub fn move_to_previous_word_start(
12788        &mut self,
12789        _: &MoveToPreviousWordStart,
12790        window: &mut Window,
12791        cx: &mut Context<Self>,
12792    ) {
12793        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12794        self.change_selections(Default::default(), window, cx, |s| {
12795            s.move_cursors_with(|map, head, _| {
12796                (
12797                    movement::previous_word_start(map, head),
12798                    SelectionGoal::None,
12799                )
12800            });
12801        })
12802    }
12803
12804    pub fn move_to_previous_subword_start(
12805        &mut self,
12806        _: &MoveToPreviousSubwordStart,
12807        window: &mut Window,
12808        cx: &mut Context<Self>,
12809    ) {
12810        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12811        self.change_selections(Default::default(), window, cx, |s| {
12812            s.move_cursors_with(|map, head, _| {
12813                (
12814                    movement::previous_subword_start(map, head),
12815                    SelectionGoal::None,
12816                )
12817            });
12818        })
12819    }
12820
12821    pub fn select_to_previous_word_start(
12822        &mut self,
12823        _: &SelectToPreviousWordStart,
12824        window: &mut Window,
12825        cx: &mut Context<Self>,
12826    ) {
12827        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12828        self.change_selections(Default::default(), window, cx, |s| {
12829            s.move_heads_with(|map, head, _| {
12830                (
12831                    movement::previous_word_start(map, head),
12832                    SelectionGoal::None,
12833                )
12834            });
12835        })
12836    }
12837
12838    pub fn select_to_previous_subword_start(
12839        &mut self,
12840        _: &SelectToPreviousSubwordStart,
12841        window: &mut Window,
12842        cx: &mut Context<Self>,
12843    ) {
12844        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12845        self.change_selections(Default::default(), window, cx, |s| {
12846            s.move_heads_with(|map, head, _| {
12847                (
12848                    movement::previous_subword_start(map, head),
12849                    SelectionGoal::None,
12850                )
12851            });
12852        })
12853    }
12854
12855    pub fn delete_to_previous_word_start(
12856        &mut self,
12857        action: &DeleteToPreviousWordStart,
12858        window: &mut Window,
12859        cx: &mut Context<Self>,
12860    ) {
12861        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12862        self.transact(window, cx, |this, window, cx| {
12863            this.select_autoclose_pair(window, cx);
12864            this.change_selections(Default::default(), window, cx, |s| {
12865                s.move_with(|map, selection| {
12866                    if selection.is_empty() {
12867                        let cursor = if action.ignore_newlines {
12868                            movement::previous_word_start(map, selection.head())
12869                        } else {
12870                            movement::previous_word_start_or_newline(map, selection.head())
12871                        };
12872                        selection.set_head(cursor, SelectionGoal::None);
12873                    }
12874                });
12875            });
12876            this.insert("", window, cx);
12877        });
12878    }
12879
12880    pub fn delete_to_previous_subword_start(
12881        &mut self,
12882        _: &DeleteToPreviousSubwordStart,
12883        window: &mut Window,
12884        cx: &mut Context<Self>,
12885    ) {
12886        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12887        self.transact(window, cx, |this, window, cx| {
12888            this.select_autoclose_pair(window, cx);
12889            this.change_selections(Default::default(), window, cx, |s| {
12890                s.move_with(|map, selection| {
12891                    if selection.is_empty() {
12892                        let cursor = movement::previous_subword_start(map, selection.head());
12893                        selection.set_head(cursor, SelectionGoal::None);
12894                    }
12895                });
12896            });
12897            this.insert("", window, cx);
12898        });
12899    }
12900
12901    pub fn move_to_next_word_end(
12902        &mut self,
12903        _: &MoveToNextWordEnd,
12904        window: &mut Window,
12905        cx: &mut Context<Self>,
12906    ) {
12907        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12908        self.change_selections(Default::default(), window, cx, |s| {
12909            s.move_cursors_with(|map, head, _| {
12910                (movement::next_word_end(map, head), SelectionGoal::None)
12911            });
12912        })
12913    }
12914
12915    pub fn move_to_next_subword_end(
12916        &mut self,
12917        _: &MoveToNextSubwordEnd,
12918        window: &mut Window,
12919        cx: &mut Context<Self>,
12920    ) {
12921        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12922        self.change_selections(Default::default(), window, cx, |s| {
12923            s.move_cursors_with(|map, head, _| {
12924                (movement::next_subword_end(map, head), SelectionGoal::None)
12925            });
12926        })
12927    }
12928
12929    pub fn select_to_next_word_end(
12930        &mut self,
12931        _: &SelectToNextWordEnd,
12932        window: &mut Window,
12933        cx: &mut Context<Self>,
12934    ) {
12935        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12936        self.change_selections(Default::default(), window, cx, |s| {
12937            s.move_heads_with(|map, head, _| {
12938                (movement::next_word_end(map, head), SelectionGoal::None)
12939            });
12940        })
12941    }
12942
12943    pub fn select_to_next_subword_end(
12944        &mut self,
12945        _: &SelectToNextSubwordEnd,
12946        window: &mut Window,
12947        cx: &mut Context<Self>,
12948    ) {
12949        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12950        self.change_selections(Default::default(), window, cx, |s| {
12951            s.move_heads_with(|map, head, _| {
12952                (movement::next_subword_end(map, head), SelectionGoal::None)
12953            });
12954        })
12955    }
12956
12957    pub fn delete_to_next_word_end(
12958        &mut self,
12959        action: &DeleteToNextWordEnd,
12960        window: &mut Window,
12961        cx: &mut Context<Self>,
12962    ) {
12963        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12964        self.transact(window, cx, |this, window, cx| {
12965            this.change_selections(Default::default(), window, cx, |s| {
12966                s.move_with(|map, selection| {
12967                    if selection.is_empty() {
12968                        let cursor = if action.ignore_newlines {
12969                            movement::next_word_end(map, selection.head())
12970                        } else {
12971                            movement::next_word_end_or_newline(map, selection.head())
12972                        };
12973                        selection.set_head(cursor, SelectionGoal::None);
12974                    }
12975                });
12976            });
12977            this.insert("", window, cx);
12978        });
12979    }
12980
12981    pub fn delete_to_next_subword_end(
12982        &mut self,
12983        _: &DeleteToNextSubwordEnd,
12984        window: &mut Window,
12985        cx: &mut Context<Self>,
12986    ) {
12987        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12988        self.transact(window, cx, |this, window, cx| {
12989            this.change_selections(Default::default(), window, cx, |s| {
12990                s.move_with(|map, selection| {
12991                    if selection.is_empty() {
12992                        let cursor = movement::next_subword_end(map, selection.head());
12993                        selection.set_head(cursor, SelectionGoal::None);
12994                    }
12995                });
12996            });
12997            this.insert("", window, cx);
12998        });
12999    }
13000
13001    pub fn move_to_beginning_of_line(
13002        &mut self,
13003        action: &MoveToBeginningOfLine,
13004        window: &mut Window,
13005        cx: &mut Context<Self>,
13006    ) {
13007        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13008        self.change_selections(Default::default(), window, cx, |s| {
13009            s.move_cursors_with(|map, head, _| {
13010                (
13011                    movement::indented_line_beginning(
13012                        map,
13013                        head,
13014                        action.stop_at_soft_wraps,
13015                        action.stop_at_indent,
13016                    ),
13017                    SelectionGoal::None,
13018                )
13019            });
13020        })
13021    }
13022
13023    pub fn select_to_beginning_of_line(
13024        &mut self,
13025        action: &SelectToBeginningOfLine,
13026        window: &mut Window,
13027        cx: &mut Context<Self>,
13028    ) {
13029        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13030        self.change_selections(Default::default(), window, cx, |s| {
13031            s.move_heads_with(|map, head, _| {
13032                (
13033                    movement::indented_line_beginning(
13034                        map,
13035                        head,
13036                        action.stop_at_soft_wraps,
13037                        action.stop_at_indent,
13038                    ),
13039                    SelectionGoal::None,
13040                )
13041            });
13042        });
13043    }
13044
13045    pub fn delete_to_beginning_of_line(
13046        &mut self,
13047        action: &DeleteToBeginningOfLine,
13048        window: &mut Window,
13049        cx: &mut Context<Self>,
13050    ) {
13051        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13052        self.transact(window, cx, |this, window, cx| {
13053            this.change_selections(Default::default(), window, cx, |s| {
13054                s.move_with(|_, selection| {
13055                    selection.reversed = true;
13056                });
13057            });
13058
13059            this.select_to_beginning_of_line(
13060                &SelectToBeginningOfLine {
13061                    stop_at_soft_wraps: false,
13062                    stop_at_indent: action.stop_at_indent,
13063                },
13064                window,
13065                cx,
13066            );
13067            this.backspace(&Backspace, window, cx);
13068        });
13069    }
13070
13071    pub fn move_to_end_of_line(
13072        &mut self,
13073        action: &MoveToEndOfLine,
13074        window: &mut Window,
13075        cx: &mut Context<Self>,
13076    ) {
13077        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13078        self.change_selections(Default::default(), window, cx, |s| {
13079            s.move_cursors_with(|map, head, _| {
13080                (
13081                    movement::line_end(map, head, action.stop_at_soft_wraps),
13082                    SelectionGoal::None,
13083                )
13084            });
13085        })
13086    }
13087
13088    pub fn select_to_end_of_line(
13089        &mut self,
13090        action: &SelectToEndOfLine,
13091        window: &mut Window,
13092        cx: &mut Context<Self>,
13093    ) {
13094        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13095        self.change_selections(Default::default(), window, cx, |s| {
13096            s.move_heads_with(|map, head, _| {
13097                (
13098                    movement::line_end(map, head, action.stop_at_soft_wraps),
13099                    SelectionGoal::None,
13100                )
13101            });
13102        })
13103    }
13104
13105    pub fn delete_to_end_of_line(
13106        &mut self,
13107        _: &DeleteToEndOfLine,
13108        window: &mut Window,
13109        cx: &mut Context<Self>,
13110    ) {
13111        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13112        self.transact(window, cx, |this, window, cx| {
13113            this.select_to_end_of_line(
13114                &SelectToEndOfLine {
13115                    stop_at_soft_wraps: false,
13116                },
13117                window,
13118                cx,
13119            );
13120            this.delete(&Delete, window, cx);
13121        });
13122    }
13123
13124    pub fn cut_to_end_of_line(
13125        &mut self,
13126        _: &CutToEndOfLine,
13127        window: &mut Window,
13128        cx: &mut Context<Self>,
13129    ) {
13130        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13131        self.transact(window, cx, |this, window, cx| {
13132            this.select_to_end_of_line(
13133                &SelectToEndOfLine {
13134                    stop_at_soft_wraps: false,
13135                },
13136                window,
13137                cx,
13138            );
13139            this.cut(&Cut, window, cx);
13140        });
13141    }
13142
13143    pub fn move_to_start_of_paragraph(
13144        &mut self,
13145        _: &MoveToStartOfParagraph,
13146        window: &mut Window,
13147        cx: &mut Context<Self>,
13148    ) {
13149        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13150            cx.propagate();
13151            return;
13152        }
13153        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13154        self.change_selections(Default::default(), window, cx, |s| {
13155            s.move_with(|map, selection| {
13156                selection.collapse_to(
13157                    movement::start_of_paragraph(map, selection.head(), 1),
13158                    SelectionGoal::None,
13159                )
13160            });
13161        })
13162    }
13163
13164    pub fn move_to_end_of_paragraph(
13165        &mut self,
13166        _: &MoveToEndOfParagraph,
13167        window: &mut Window,
13168        cx: &mut Context<Self>,
13169    ) {
13170        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13171            cx.propagate();
13172            return;
13173        }
13174        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13175        self.change_selections(Default::default(), window, cx, |s| {
13176            s.move_with(|map, selection| {
13177                selection.collapse_to(
13178                    movement::end_of_paragraph(map, selection.head(), 1),
13179                    SelectionGoal::None,
13180                )
13181            });
13182        })
13183    }
13184
13185    pub fn select_to_start_of_paragraph(
13186        &mut self,
13187        _: &SelectToStartOfParagraph,
13188        window: &mut Window,
13189        cx: &mut Context<Self>,
13190    ) {
13191        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13192            cx.propagate();
13193            return;
13194        }
13195        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13196        self.change_selections(Default::default(), window, cx, |s| {
13197            s.move_heads_with(|map, head, _| {
13198                (
13199                    movement::start_of_paragraph(map, head, 1),
13200                    SelectionGoal::None,
13201                )
13202            });
13203        })
13204    }
13205
13206    pub fn select_to_end_of_paragraph(
13207        &mut self,
13208        _: &SelectToEndOfParagraph,
13209        window: &mut Window,
13210        cx: &mut Context<Self>,
13211    ) {
13212        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13213            cx.propagate();
13214            return;
13215        }
13216        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13217        self.change_selections(Default::default(), window, cx, |s| {
13218            s.move_heads_with(|map, head, _| {
13219                (
13220                    movement::end_of_paragraph(map, head, 1),
13221                    SelectionGoal::None,
13222                )
13223            });
13224        })
13225    }
13226
13227    pub fn move_to_start_of_excerpt(
13228        &mut self,
13229        _: &MoveToStartOfExcerpt,
13230        window: &mut Window,
13231        cx: &mut Context<Self>,
13232    ) {
13233        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13234            cx.propagate();
13235            return;
13236        }
13237        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13238        self.change_selections(Default::default(), window, cx, |s| {
13239            s.move_with(|map, selection| {
13240                selection.collapse_to(
13241                    movement::start_of_excerpt(
13242                        map,
13243                        selection.head(),
13244                        workspace::searchable::Direction::Prev,
13245                    ),
13246                    SelectionGoal::None,
13247                )
13248            });
13249        })
13250    }
13251
13252    pub fn move_to_start_of_next_excerpt(
13253        &mut self,
13254        _: &MoveToStartOfNextExcerpt,
13255        window: &mut Window,
13256        cx: &mut Context<Self>,
13257    ) {
13258        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13259            cx.propagate();
13260            return;
13261        }
13262
13263        self.change_selections(Default::default(), window, cx, |s| {
13264            s.move_with(|map, selection| {
13265                selection.collapse_to(
13266                    movement::start_of_excerpt(
13267                        map,
13268                        selection.head(),
13269                        workspace::searchable::Direction::Next,
13270                    ),
13271                    SelectionGoal::None,
13272                )
13273            });
13274        })
13275    }
13276
13277    pub fn move_to_end_of_excerpt(
13278        &mut self,
13279        _: &MoveToEndOfExcerpt,
13280        window: &mut Window,
13281        cx: &mut Context<Self>,
13282    ) {
13283        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13284            cx.propagate();
13285            return;
13286        }
13287        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13288        self.change_selections(Default::default(), window, cx, |s| {
13289            s.move_with(|map, selection| {
13290                selection.collapse_to(
13291                    movement::end_of_excerpt(
13292                        map,
13293                        selection.head(),
13294                        workspace::searchable::Direction::Next,
13295                    ),
13296                    SelectionGoal::None,
13297                )
13298            });
13299        })
13300    }
13301
13302    pub fn move_to_end_of_previous_excerpt(
13303        &mut self,
13304        _: &MoveToEndOfPreviousExcerpt,
13305        window: &mut Window,
13306        cx: &mut Context<Self>,
13307    ) {
13308        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13309            cx.propagate();
13310            return;
13311        }
13312        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13313        self.change_selections(Default::default(), window, cx, |s| {
13314            s.move_with(|map, selection| {
13315                selection.collapse_to(
13316                    movement::end_of_excerpt(
13317                        map,
13318                        selection.head(),
13319                        workspace::searchable::Direction::Prev,
13320                    ),
13321                    SelectionGoal::None,
13322                )
13323            });
13324        })
13325    }
13326
13327    pub fn select_to_start_of_excerpt(
13328        &mut self,
13329        _: &SelectToStartOfExcerpt,
13330        window: &mut Window,
13331        cx: &mut Context<Self>,
13332    ) {
13333        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13334            cx.propagate();
13335            return;
13336        }
13337        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13338        self.change_selections(Default::default(), window, cx, |s| {
13339            s.move_heads_with(|map, head, _| {
13340                (
13341                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13342                    SelectionGoal::None,
13343                )
13344            });
13345        })
13346    }
13347
13348    pub fn select_to_start_of_next_excerpt(
13349        &mut self,
13350        _: &SelectToStartOfNextExcerpt,
13351        window: &mut Window,
13352        cx: &mut Context<Self>,
13353    ) {
13354        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13355            cx.propagate();
13356            return;
13357        }
13358        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13359        self.change_selections(Default::default(), window, cx, |s| {
13360            s.move_heads_with(|map, head, _| {
13361                (
13362                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13363                    SelectionGoal::None,
13364                )
13365            });
13366        })
13367    }
13368
13369    pub fn select_to_end_of_excerpt(
13370        &mut self,
13371        _: &SelectToEndOfExcerpt,
13372        window: &mut Window,
13373        cx: &mut Context<Self>,
13374    ) {
13375        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13376            cx.propagate();
13377            return;
13378        }
13379        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13380        self.change_selections(Default::default(), window, cx, |s| {
13381            s.move_heads_with(|map, head, _| {
13382                (
13383                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13384                    SelectionGoal::None,
13385                )
13386            });
13387        })
13388    }
13389
13390    pub fn select_to_end_of_previous_excerpt(
13391        &mut self,
13392        _: &SelectToEndOfPreviousExcerpt,
13393        window: &mut Window,
13394        cx: &mut Context<Self>,
13395    ) {
13396        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13397            cx.propagate();
13398            return;
13399        }
13400        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13401        self.change_selections(Default::default(), window, cx, |s| {
13402            s.move_heads_with(|map, head, _| {
13403                (
13404                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13405                    SelectionGoal::None,
13406                )
13407            });
13408        })
13409    }
13410
13411    pub fn move_to_beginning(
13412        &mut self,
13413        _: &MoveToBeginning,
13414        window: &mut Window,
13415        cx: &mut Context<Self>,
13416    ) {
13417        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13418            cx.propagate();
13419            return;
13420        }
13421        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13422        self.change_selections(Default::default(), window, cx, |s| {
13423            s.select_ranges(vec![0..0]);
13424        });
13425    }
13426
13427    pub fn select_to_beginning(
13428        &mut self,
13429        _: &SelectToBeginning,
13430        window: &mut Window,
13431        cx: &mut Context<Self>,
13432    ) {
13433        let mut selection = self.selections.last::<Point>(cx);
13434        selection.set_head(Point::zero(), SelectionGoal::None);
13435        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13436        self.change_selections(Default::default(), window, cx, |s| {
13437            s.select(vec![selection]);
13438        });
13439    }
13440
13441    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13442        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13443            cx.propagate();
13444            return;
13445        }
13446        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13447        let cursor = self.buffer.read(cx).read(cx).len();
13448        self.change_selections(Default::default(), window, cx, |s| {
13449            s.select_ranges(vec![cursor..cursor])
13450        });
13451    }
13452
13453    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13454        self.nav_history = nav_history;
13455    }
13456
13457    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13458        self.nav_history.as_ref()
13459    }
13460
13461    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13462        self.push_to_nav_history(
13463            self.selections.newest_anchor().head(),
13464            None,
13465            false,
13466            true,
13467            cx,
13468        );
13469    }
13470
13471    fn push_to_nav_history(
13472        &mut self,
13473        cursor_anchor: Anchor,
13474        new_position: Option<Point>,
13475        is_deactivate: bool,
13476        always: bool,
13477        cx: &mut Context<Self>,
13478    ) {
13479        if let Some(nav_history) = self.nav_history.as_mut() {
13480            let buffer = self.buffer.read(cx).read(cx);
13481            let cursor_position = cursor_anchor.to_point(&buffer);
13482            let scroll_state = self.scroll_manager.anchor();
13483            let scroll_top_row = scroll_state.top_row(&buffer);
13484            drop(buffer);
13485
13486            if let Some(new_position) = new_position {
13487                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13488                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13489                    return;
13490                }
13491            }
13492
13493            nav_history.push(
13494                Some(NavigationData {
13495                    cursor_anchor,
13496                    cursor_position,
13497                    scroll_anchor: scroll_state,
13498                    scroll_top_row,
13499                }),
13500                cx,
13501            );
13502            cx.emit(EditorEvent::PushedToNavHistory {
13503                anchor: cursor_anchor,
13504                is_deactivate,
13505            })
13506        }
13507    }
13508
13509    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13510        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13511        let buffer = self.buffer.read(cx).snapshot(cx);
13512        let mut selection = self.selections.first::<usize>(cx);
13513        selection.set_head(buffer.len(), SelectionGoal::None);
13514        self.change_selections(Default::default(), window, cx, |s| {
13515            s.select(vec![selection]);
13516        });
13517    }
13518
13519    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13520        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13521        let end = self.buffer.read(cx).read(cx).len();
13522        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13523            s.select_ranges(vec![0..end]);
13524        });
13525    }
13526
13527    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13528        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13529        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13530        let mut selections = self.selections.all::<Point>(cx);
13531        let max_point = display_map.buffer_snapshot.max_point();
13532        for selection in &mut selections {
13533            let rows = selection.spanned_rows(true, &display_map);
13534            selection.start = Point::new(rows.start.0, 0);
13535            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13536            selection.reversed = false;
13537        }
13538        self.change_selections(Default::default(), window, cx, |s| {
13539            s.select(selections);
13540        });
13541    }
13542
13543    pub fn split_selection_into_lines(
13544        &mut self,
13545        _: &SplitSelectionIntoLines,
13546        window: &mut Window,
13547        cx: &mut Context<Self>,
13548    ) {
13549        let selections = self
13550            .selections
13551            .all::<Point>(cx)
13552            .into_iter()
13553            .map(|selection| selection.start..selection.end)
13554            .collect::<Vec<_>>();
13555        self.unfold_ranges(&selections, true, true, cx);
13556
13557        let mut new_selection_ranges = Vec::new();
13558        {
13559            let buffer = self.buffer.read(cx).read(cx);
13560            for selection in selections {
13561                for row in selection.start.row..selection.end.row {
13562                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13563                    new_selection_ranges.push(cursor..cursor);
13564                }
13565
13566                let is_multiline_selection = selection.start.row != selection.end.row;
13567                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13568                // so this action feels more ergonomic when paired with other selection operations
13569                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13570                if !should_skip_last {
13571                    new_selection_ranges.push(selection.end..selection.end);
13572                }
13573            }
13574        }
13575        self.change_selections(Default::default(), window, cx, |s| {
13576            s.select_ranges(new_selection_ranges);
13577        });
13578    }
13579
13580    pub fn add_selection_above(
13581        &mut self,
13582        _: &AddSelectionAbove,
13583        window: &mut Window,
13584        cx: &mut Context<Self>,
13585    ) {
13586        self.add_selection(true, window, cx);
13587    }
13588
13589    pub fn add_selection_below(
13590        &mut self,
13591        _: &AddSelectionBelow,
13592        window: &mut Window,
13593        cx: &mut Context<Self>,
13594    ) {
13595        self.add_selection(false, window, cx);
13596    }
13597
13598    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13599        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13600
13601        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13602        let all_selections = self.selections.all::<Point>(cx);
13603        let text_layout_details = self.text_layout_details(window);
13604
13605        let (mut columnar_selections, new_selections_to_columnarize) = {
13606            if let Some(state) = self.add_selections_state.as_ref() {
13607                let columnar_selection_ids: HashSet<_> = state
13608                    .groups
13609                    .iter()
13610                    .flat_map(|group| group.stack.iter())
13611                    .copied()
13612                    .collect();
13613
13614                all_selections
13615                    .into_iter()
13616                    .partition(|s| columnar_selection_ids.contains(&s.id))
13617            } else {
13618                (Vec::new(), all_selections)
13619            }
13620        };
13621
13622        let mut state = self
13623            .add_selections_state
13624            .take()
13625            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13626
13627        for selection in new_selections_to_columnarize {
13628            let range = selection.display_range(&display_map).sorted();
13629            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13630            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13631            let positions = start_x.min(end_x)..start_x.max(end_x);
13632            let mut stack = Vec::new();
13633            for row in range.start.row().0..=range.end.row().0 {
13634                if let Some(selection) = self.selections.build_columnar_selection(
13635                    &display_map,
13636                    DisplayRow(row),
13637                    &positions,
13638                    selection.reversed,
13639                    &text_layout_details,
13640                ) {
13641                    stack.push(selection.id);
13642                    columnar_selections.push(selection);
13643                }
13644            }
13645            if !stack.is_empty() {
13646                if above {
13647                    stack.reverse();
13648                }
13649                state.groups.push(AddSelectionsGroup { above, stack });
13650            }
13651        }
13652
13653        let mut final_selections = Vec::new();
13654        let end_row = if above {
13655            DisplayRow(0)
13656        } else {
13657            display_map.max_point().row()
13658        };
13659
13660        let mut last_added_item_per_group = HashMap::default();
13661        for group in state.groups.iter_mut() {
13662            if let Some(last_id) = group.stack.last() {
13663                last_added_item_per_group.insert(*last_id, group);
13664            }
13665        }
13666
13667        for selection in columnar_selections {
13668            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13669                if above == group.above {
13670                    let range = selection.display_range(&display_map).sorted();
13671                    debug_assert_eq!(range.start.row(), range.end.row());
13672                    let mut row = range.start.row();
13673                    let positions =
13674                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13675                            px(start)..px(end)
13676                        } else {
13677                            let start_x =
13678                                display_map.x_for_display_point(range.start, &text_layout_details);
13679                            let end_x =
13680                                display_map.x_for_display_point(range.end, &text_layout_details);
13681                            start_x.min(end_x)..start_x.max(end_x)
13682                        };
13683
13684                    let mut maybe_new_selection = None;
13685                    while row != end_row {
13686                        if above {
13687                            row.0 -= 1;
13688                        } else {
13689                            row.0 += 1;
13690                        }
13691                        if let Some(new_selection) = self.selections.build_columnar_selection(
13692                            &display_map,
13693                            row,
13694                            &positions,
13695                            selection.reversed,
13696                            &text_layout_details,
13697                        ) {
13698                            maybe_new_selection = Some(new_selection);
13699                            break;
13700                        }
13701                    }
13702
13703                    if let Some(new_selection) = maybe_new_selection {
13704                        group.stack.push(new_selection.id);
13705                        if above {
13706                            final_selections.push(new_selection);
13707                            final_selections.push(selection);
13708                        } else {
13709                            final_selections.push(selection);
13710                            final_selections.push(new_selection);
13711                        }
13712                    } else {
13713                        final_selections.push(selection);
13714                    }
13715                } else {
13716                    group.stack.pop();
13717                }
13718            } else {
13719                final_selections.push(selection);
13720            }
13721        }
13722
13723        self.change_selections(Default::default(), window, cx, |s| {
13724            s.select(final_selections);
13725        });
13726
13727        let final_selection_ids: HashSet<_> = self
13728            .selections
13729            .all::<Point>(cx)
13730            .iter()
13731            .map(|s| s.id)
13732            .collect();
13733        state.groups.retain_mut(|group| {
13734            // selections might get merged above so we remove invalid items from stacks
13735            group.stack.retain(|id| final_selection_ids.contains(id));
13736
13737            // single selection in stack can be treated as initial state
13738            group.stack.len() > 1
13739        });
13740
13741        if !state.groups.is_empty() {
13742            self.add_selections_state = Some(state);
13743        }
13744    }
13745
13746    fn select_match_ranges(
13747        &mut self,
13748        range: Range<usize>,
13749        reversed: bool,
13750        replace_newest: bool,
13751        auto_scroll: Option<Autoscroll>,
13752        window: &mut Window,
13753        cx: &mut Context<Editor>,
13754    ) {
13755        self.unfold_ranges(
13756            std::slice::from_ref(&range),
13757            false,
13758            auto_scroll.is_some(),
13759            cx,
13760        );
13761        let effects = if let Some(scroll) = auto_scroll {
13762            SelectionEffects::scroll(scroll)
13763        } else {
13764            SelectionEffects::no_scroll()
13765        };
13766        self.change_selections(effects, window, cx, |s| {
13767            if replace_newest {
13768                s.delete(s.newest_anchor().id);
13769            }
13770            if reversed {
13771                s.insert_range(range.end..range.start);
13772            } else {
13773                s.insert_range(range);
13774            }
13775        });
13776    }
13777
13778    pub fn select_next_match_internal(
13779        &mut self,
13780        display_map: &DisplaySnapshot,
13781        replace_newest: bool,
13782        autoscroll: Option<Autoscroll>,
13783        window: &mut Window,
13784        cx: &mut Context<Self>,
13785    ) -> Result<()> {
13786        let buffer = &display_map.buffer_snapshot;
13787        let mut selections = self.selections.all::<usize>(cx);
13788        if let Some(mut select_next_state) = self.select_next_state.take() {
13789            let query = &select_next_state.query;
13790            if !select_next_state.done {
13791                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13792                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13793                let mut next_selected_range = None;
13794
13795                let bytes_after_last_selection =
13796                    buffer.bytes_in_range(last_selection.end..buffer.len());
13797                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13798                let query_matches = query
13799                    .stream_find_iter(bytes_after_last_selection)
13800                    .map(|result| (last_selection.end, result))
13801                    .chain(
13802                        query
13803                            .stream_find_iter(bytes_before_first_selection)
13804                            .map(|result| (0, result)),
13805                    );
13806
13807                for (start_offset, query_match) in query_matches {
13808                    let query_match = query_match.unwrap(); // can only fail due to I/O
13809                    let offset_range =
13810                        start_offset + query_match.start()..start_offset + query_match.end();
13811
13812                    if !select_next_state.wordwise
13813                        || (!buffer.is_inside_word(offset_range.start, false)
13814                            && !buffer.is_inside_word(offset_range.end, false))
13815                    {
13816                        // TODO: This is n^2, because we might check all the selections
13817                        if !selections
13818                            .iter()
13819                            .any(|selection| selection.range().overlaps(&offset_range))
13820                        {
13821                            next_selected_range = Some(offset_range);
13822                            break;
13823                        }
13824                    }
13825                }
13826
13827                if let Some(next_selected_range) = next_selected_range {
13828                    self.select_match_ranges(
13829                        next_selected_range,
13830                        last_selection.reversed,
13831                        replace_newest,
13832                        autoscroll,
13833                        window,
13834                        cx,
13835                    );
13836                } else {
13837                    select_next_state.done = true;
13838                }
13839            }
13840
13841            self.select_next_state = Some(select_next_state);
13842        } else {
13843            let mut only_carets = true;
13844            let mut same_text_selected = true;
13845            let mut selected_text = None;
13846
13847            let mut selections_iter = selections.iter().peekable();
13848            while let Some(selection) = selections_iter.next() {
13849                if selection.start != selection.end {
13850                    only_carets = false;
13851                }
13852
13853                if same_text_selected {
13854                    if selected_text.is_none() {
13855                        selected_text =
13856                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13857                    }
13858
13859                    if let Some(next_selection) = selections_iter.peek() {
13860                        if next_selection.range().len() == selection.range().len() {
13861                            let next_selected_text = buffer
13862                                .text_for_range(next_selection.range())
13863                                .collect::<String>();
13864                            if Some(next_selected_text) != selected_text {
13865                                same_text_selected = false;
13866                                selected_text = None;
13867                            }
13868                        } else {
13869                            same_text_selected = false;
13870                            selected_text = None;
13871                        }
13872                    }
13873                }
13874            }
13875
13876            if only_carets {
13877                for selection in &mut selections {
13878                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13879                    selection.start = word_range.start;
13880                    selection.end = word_range.end;
13881                    selection.goal = SelectionGoal::None;
13882                    selection.reversed = false;
13883                    self.select_match_ranges(
13884                        selection.start..selection.end,
13885                        selection.reversed,
13886                        replace_newest,
13887                        autoscroll,
13888                        window,
13889                        cx,
13890                    );
13891                }
13892
13893                if selections.len() == 1 {
13894                    let selection = selections
13895                        .last()
13896                        .expect("ensured that there's only one selection");
13897                    let query = buffer
13898                        .text_for_range(selection.start..selection.end)
13899                        .collect::<String>();
13900                    let is_empty = query.is_empty();
13901                    let select_state = SelectNextState {
13902                        query: AhoCorasick::new(&[query])?,
13903                        wordwise: true,
13904                        done: is_empty,
13905                    };
13906                    self.select_next_state = Some(select_state);
13907                } else {
13908                    self.select_next_state = None;
13909                }
13910            } else if let Some(selected_text) = selected_text {
13911                self.select_next_state = Some(SelectNextState {
13912                    query: AhoCorasick::new(&[selected_text])?,
13913                    wordwise: false,
13914                    done: false,
13915                });
13916                self.select_next_match_internal(
13917                    display_map,
13918                    replace_newest,
13919                    autoscroll,
13920                    window,
13921                    cx,
13922                )?;
13923            }
13924        }
13925        Ok(())
13926    }
13927
13928    pub fn select_all_matches(
13929        &mut self,
13930        _action: &SelectAllMatches,
13931        window: &mut Window,
13932        cx: &mut Context<Self>,
13933    ) -> Result<()> {
13934        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13935
13936        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13937
13938        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13939        let Some(select_next_state) = self.select_next_state.as_mut() else {
13940            return Ok(());
13941        };
13942        if select_next_state.done {
13943            return Ok(());
13944        }
13945
13946        let mut new_selections = Vec::new();
13947
13948        let reversed = self.selections.oldest::<usize>(cx).reversed;
13949        let buffer = &display_map.buffer_snapshot;
13950        let query_matches = select_next_state
13951            .query
13952            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13953
13954        for query_match in query_matches.into_iter() {
13955            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13956            let offset_range = if reversed {
13957                query_match.end()..query_match.start()
13958            } else {
13959                query_match.start()..query_match.end()
13960            };
13961
13962            if !select_next_state.wordwise
13963                || (!buffer.is_inside_word(offset_range.start, false)
13964                    && !buffer.is_inside_word(offset_range.end, false))
13965            {
13966                new_selections.push(offset_range.start..offset_range.end);
13967            }
13968        }
13969
13970        select_next_state.done = true;
13971
13972        if new_selections.is_empty() {
13973            log::error!("bug: new_selections is empty in select_all_matches");
13974            return Ok(());
13975        }
13976
13977        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13978        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
13979            selections.select_ranges(new_selections)
13980        });
13981
13982        Ok(())
13983    }
13984
13985    pub fn select_next(
13986        &mut self,
13987        action: &SelectNext,
13988        window: &mut Window,
13989        cx: &mut Context<Self>,
13990    ) -> Result<()> {
13991        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13992        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13993        self.select_next_match_internal(
13994            &display_map,
13995            action.replace_newest,
13996            Some(Autoscroll::newest()),
13997            window,
13998            cx,
13999        )?;
14000        Ok(())
14001    }
14002
14003    pub fn select_previous(
14004        &mut self,
14005        action: &SelectPrevious,
14006        window: &mut Window,
14007        cx: &mut Context<Self>,
14008    ) -> Result<()> {
14009        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14010        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14011        let buffer = &display_map.buffer_snapshot;
14012        let mut selections = self.selections.all::<usize>(cx);
14013        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14014            let query = &select_prev_state.query;
14015            if !select_prev_state.done {
14016                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14017                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14018                let mut next_selected_range = None;
14019                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14020                let bytes_before_last_selection =
14021                    buffer.reversed_bytes_in_range(0..last_selection.start);
14022                let bytes_after_first_selection =
14023                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14024                let query_matches = query
14025                    .stream_find_iter(bytes_before_last_selection)
14026                    .map(|result| (last_selection.start, result))
14027                    .chain(
14028                        query
14029                            .stream_find_iter(bytes_after_first_selection)
14030                            .map(|result| (buffer.len(), result)),
14031                    );
14032                for (end_offset, query_match) in query_matches {
14033                    let query_match = query_match.unwrap(); // can only fail due to I/O
14034                    let offset_range =
14035                        end_offset - query_match.end()..end_offset - query_match.start();
14036
14037                    if !select_prev_state.wordwise
14038                        || (!buffer.is_inside_word(offset_range.start, false)
14039                            && !buffer.is_inside_word(offset_range.end, false))
14040                    {
14041                        next_selected_range = Some(offset_range);
14042                        break;
14043                    }
14044                }
14045
14046                if let Some(next_selected_range) = next_selected_range {
14047                    self.select_match_ranges(
14048                        next_selected_range,
14049                        last_selection.reversed,
14050                        action.replace_newest,
14051                        Some(Autoscroll::newest()),
14052                        window,
14053                        cx,
14054                    );
14055                } else {
14056                    select_prev_state.done = true;
14057                }
14058            }
14059
14060            self.select_prev_state = Some(select_prev_state);
14061        } else {
14062            let mut only_carets = true;
14063            let mut same_text_selected = true;
14064            let mut selected_text = None;
14065
14066            let mut selections_iter = selections.iter().peekable();
14067            while let Some(selection) = selections_iter.next() {
14068                if selection.start != selection.end {
14069                    only_carets = false;
14070                }
14071
14072                if same_text_selected {
14073                    if selected_text.is_none() {
14074                        selected_text =
14075                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14076                    }
14077
14078                    if let Some(next_selection) = selections_iter.peek() {
14079                        if next_selection.range().len() == selection.range().len() {
14080                            let next_selected_text = buffer
14081                                .text_for_range(next_selection.range())
14082                                .collect::<String>();
14083                            if Some(next_selected_text) != selected_text {
14084                                same_text_selected = false;
14085                                selected_text = None;
14086                            }
14087                        } else {
14088                            same_text_selected = false;
14089                            selected_text = None;
14090                        }
14091                    }
14092                }
14093            }
14094
14095            if only_carets {
14096                for selection in &mut selections {
14097                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14098                    selection.start = word_range.start;
14099                    selection.end = word_range.end;
14100                    selection.goal = SelectionGoal::None;
14101                    selection.reversed = false;
14102                    self.select_match_ranges(
14103                        selection.start..selection.end,
14104                        selection.reversed,
14105                        action.replace_newest,
14106                        Some(Autoscroll::newest()),
14107                        window,
14108                        cx,
14109                    );
14110                }
14111                if selections.len() == 1 {
14112                    let selection = selections
14113                        .last()
14114                        .expect("ensured that there's only one selection");
14115                    let query = buffer
14116                        .text_for_range(selection.start..selection.end)
14117                        .collect::<String>();
14118                    let is_empty = query.is_empty();
14119                    let select_state = SelectNextState {
14120                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14121                        wordwise: true,
14122                        done: is_empty,
14123                    };
14124                    self.select_prev_state = Some(select_state);
14125                } else {
14126                    self.select_prev_state = None;
14127                }
14128            } else if let Some(selected_text) = selected_text {
14129                self.select_prev_state = Some(SelectNextState {
14130                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14131                    wordwise: false,
14132                    done: false,
14133                });
14134                self.select_previous(action, window, cx)?;
14135            }
14136        }
14137        Ok(())
14138    }
14139
14140    pub fn find_next_match(
14141        &mut self,
14142        _: &FindNextMatch,
14143        window: &mut Window,
14144        cx: &mut Context<Self>,
14145    ) -> Result<()> {
14146        let selections = self.selections.disjoint_anchors();
14147        match selections.first() {
14148            Some(first) if selections.len() >= 2 => {
14149                self.change_selections(Default::default(), window, cx, |s| {
14150                    s.select_ranges([first.range()]);
14151                });
14152            }
14153            _ => self.select_next(
14154                &SelectNext {
14155                    replace_newest: true,
14156                },
14157                window,
14158                cx,
14159            )?,
14160        }
14161        Ok(())
14162    }
14163
14164    pub fn find_previous_match(
14165        &mut self,
14166        _: &FindPreviousMatch,
14167        window: &mut Window,
14168        cx: &mut Context<Self>,
14169    ) -> Result<()> {
14170        let selections = self.selections.disjoint_anchors();
14171        match selections.last() {
14172            Some(last) if selections.len() >= 2 => {
14173                self.change_selections(Default::default(), window, cx, |s| {
14174                    s.select_ranges([last.range()]);
14175                });
14176            }
14177            _ => self.select_previous(
14178                &SelectPrevious {
14179                    replace_newest: true,
14180                },
14181                window,
14182                cx,
14183            )?,
14184        }
14185        Ok(())
14186    }
14187
14188    pub fn toggle_comments(
14189        &mut self,
14190        action: &ToggleComments,
14191        window: &mut Window,
14192        cx: &mut Context<Self>,
14193    ) {
14194        if self.read_only(cx) {
14195            return;
14196        }
14197        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14198        let text_layout_details = &self.text_layout_details(window);
14199        self.transact(window, cx, |this, window, cx| {
14200            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14201            let mut edits = Vec::new();
14202            let mut selection_edit_ranges = Vec::new();
14203            let mut last_toggled_row = None;
14204            let snapshot = this.buffer.read(cx).read(cx);
14205            let empty_str: Arc<str> = Arc::default();
14206            let mut suffixes_inserted = Vec::new();
14207            let ignore_indent = action.ignore_indent;
14208
14209            fn comment_prefix_range(
14210                snapshot: &MultiBufferSnapshot,
14211                row: MultiBufferRow,
14212                comment_prefix: &str,
14213                comment_prefix_whitespace: &str,
14214                ignore_indent: bool,
14215            ) -> Range<Point> {
14216                let indent_size = if ignore_indent {
14217                    0
14218                } else {
14219                    snapshot.indent_size_for_line(row).len
14220                };
14221
14222                let start = Point::new(row.0, indent_size);
14223
14224                let mut line_bytes = snapshot
14225                    .bytes_in_range(start..snapshot.max_point())
14226                    .flatten()
14227                    .copied();
14228
14229                // If this line currently begins with the line comment prefix, then record
14230                // the range containing the prefix.
14231                if line_bytes
14232                    .by_ref()
14233                    .take(comment_prefix.len())
14234                    .eq(comment_prefix.bytes())
14235                {
14236                    // Include any whitespace that matches the comment prefix.
14237                    let matching_whitespace_len = line_bytes
14238                        .zip(comment_prefix_whitespace.bytes())
14239                        .take_while(|(a, b)| a == b)
14240                        .count() as u32;
14241                    let end = Point::new(
14242                        start.row,
14243                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14244                    );
14245                    start..end
14246                } else {
14247                    start..start
14248                }
14249            }
14250
14251            fn comment_suffix_range(
14252                snapshot: &MultiBufferSnapshot,
14253                row: MultiBufferRow,
14254                comment_suffix: &str,
14255                comment_suffix_has_leading_space: bool,
14256            ) -> Range<Point> {
14257                let end = Point::new(row.0, snapshot.line_len(row));
14258                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14259
14260                let mut line_end_bytes = snapshot
14261                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14262                    .flatten()
14263                    .copied();
14264
14265                let leading_space_len = if suffix_start_column > 0
14266                    && line_end_bytes.next() == Some(b' ')
14267                    && comment_suffix_has_leading_space
14268                {
14269                    1
14270                } else {
14271                    0
14272                };
14273
14274                // If this line currently begins with the line comment prefix, then record
14275                // the range containing the prefix.
14276                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14277                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14278                    start..end
14279                } else {
14280                    end..end
14281                }
14282            }
14283
14284            // TODO: Handle selections that cross excerpts
14285            for selection in &mut selections {
14286                let start_column = snapshot
14287                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14288                    .len;
14289                let language = if let Some(language) =
14290                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14291                {
14292                    language
14293                } else {
14294                    continue;
14295                };
14296
14297                selection_edit_ranges.clear();
14298
14299                // If multiple selections contain a given row, avoid processing that
14300                // row more than once.
14301                let mut start_row = MultiBufferRow(selection.start.row);
14302                if last_toggled_row == Some(start_row) {
14303                    start_row = start_row.next_row();
14304                }
14305                let end_row =
14306                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14307                        MultiBufferRow(selection.end.row - 1)
14308                    } else {
14309                        MultiBufferRow(selection.end.row)
14310                    };
14311                last_toggled_row = Some(end_row);
14312
14313                if start_row > end_row {
14314                    continue;
14315                }
14316
14317                // If the language has line comments, toggle those.
14318                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14319
14320                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14321                if ignore_indent {
14322                    full_comment_prefixes = full_comment_prefixes
14323                        .into_iter()
14324                        .map(|s| Arc::from(s.trim_end()))
14325                        .collect();
14326                }
14327
14328                if !full_comment_prefixes.is_empty() {
14329                    let first_prefix = full_comment_prefixes
14330                        .first()
14331                        .expect("prefixes is non-empty");
14332                    let prefix_trimmed_lengths = full_comment_prefixes
14333                        .iter()
14334                        .map(|p| p.trim_end_matches(' ').len())
14335                        .collect::<SmallVec<[usize; 4]>>();
14336
14337                    let mut all_selection_lines_are_comments = true;
14338
14339                    for row in start_row.0..=end_row.0 {
14340                        let row = MultiBufferRow(row);
14341                        if start_row < end_row && snapshot.is_line_blank(row) {
14342                            continue;
14343                        }
14344
14345                        let prefix_range = full_comment_prefixes
14346                            .iter()
14347                            .zip(prefix_trimmed_lengths.iter().copied())
14348                            .map(|(prefix, trimmed_prefix_len)| {
14349                                comment_prefix_range(
14350                                    snapshot.deref(),
14351                                    row,
14352                                    &prefix[..trimmed_prefix_len],
14353                                    &prefix[trimmed_prefix_len..],
14354                                    ignore_indent,
14355                                )
14356                            })
14357                            .max_by_key(|range| range.end.column - range.start.column)
14358                            .expect("prefixes is non-empty");
14359
14360                        if prefix_range.is_empty() {
14361                            all_selection_lines_are_comments = false;
14362                        }
14363
14364                        selection_edit_ranges.push(prefix_range);
14365                    }
14366
14367                    if all_selection_lines_are_comments {
14368                        edits.extend(
14369                            selection_edit_ranges
14370                                .iter()
14371                                .cloned()
14372                                .map(|range| (range, empty_str.clone())),
14373                        );
14374                    } else {
14375                        let min_column = selection_edit_ranges
14376                            .iter()
14377                            .map(|range| range.start.column)
14378                            .min()
14379                            .unwrap_or(0);
14380                        edits.extend(selection_edit_ranges.iter().map(|range| {
14381                            let position = Point::new(range.start.row, min_column);
14382                            (position..position, first_prefix.clone())
14383                        }));
14384                    }
14385                } else if let Some(BlockCommentConfig {
14386                    start: full_comment_prefix,
14387                    end: comment_suffix,
14388                    ..
14389                }) = language.block_comment()
14390                {
14391                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14392                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14393                    let prefix_range = comment_prefix_range(
14394                        snapshot.deref(),
14395                        start_row,
14396                        comment_prefix,
14397                        comment_prefix_whitespace,
14398                        ignore_indent,
14399                    );
14400                    let suffix_range = comment_suffix_range(
14401                        snapshot.deref(),
14402                        end_row,
14403                        comment_suffix.trim_start_matches(' '),
14404                        comment_suffix.starts_with(' '),
14405                    );
14406
14407                    if prefix_range.is_empty() || suffix_range.is_empty() {
14408                        edits.push((
14409                            prefix_range.start..prefix_range.start,
14410                            full_comment_prefix.clone(),
14411                        ));
14412                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14413                        suffixes_inserted.push((end_row, comment_suffix.len()));
14414                    } else {
14415                        edits.push((prefix_range, empty_str.clone()));
14416                        edits.push((suffix_range, empty_str.clone()));
14417                    }
14418                } else {
14419                    continue;
14420                }
14421            }
14422
14423            drop(snapshot);
14424            this.buffer.update(cx, |buffer, cx| {
14425                buffer.edit(edits, None, cx);
14426            });
14427
14428            // Adjust selections so that they end before any comment suffixes that
14429            // were inserted.
14430            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14431            let mut selections = this.selections.all::<Point>(cx);
14432            let snapshot = this.buffer.read(cx).read(cx);
14433            for selection in &mut selections {
14434                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14435                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14436                        Ordering::Less => {
14437                            suffixes_inserted.next();
14438                            continue;
14439                        }
14440                        Ordering::Greater => break,
14441                        Ordering::Equal => {
14442                            if selection.end.column == snapshot.line_len(row) {
14443                                if selection.is_empty() {
14444                                    selection.start.column -= suffix_len as u32;
14445                                }
14446                                selection.end.column -= suffix_len as u32;
14447                            }
14448                            break;
14449                        }
14450                    }
14451                }
14452            }
14453
14454            drop(snapshot);
14455            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14456
14457            let selections = this.selections.all::<Point>(cx);
14458            let selections_on_single_row = selections.windows(2).all(|selections| {
14459                selections[0].start.row == selections[1].start.row
14460                    && selections[0].end.row == selections[1].end.row
14461                    && selections[0].start.row == selections[0].end.row
14462            });
14463            let selections_selecting = selections
14464                .iter()
14465                .any(|selection| selection.start != selection.end);
14466            let advance_downwards = action.advance_downwards
14467                && selections_on_single_row
14468                && !selections_selecting
14469                && !matches!(this.mode, EditorMode::SingleLine { .. });
14470
14471            if advance_downwards {
14472                let snapshot = this.buffer.read(cx).snapshot(cx);
14473
14474                this.change_selections(Default::default(), window, cx, |s| {
14475                    s.move_cursors_with(|display_snapshot, display_point, _| {
14476                        let mut point = display_point.to_point(display_snapshot);
14477                        point.row += 1;
14478                        point = snapshot.clip_point(point, Bias::Left);
14479                        let display_point = point.to_display_point(display_snapshot);
14480                        let goal = SelectionGoal::HorizontalPosition(
14481                            display_snapshot
14482                                .x_for_display_point(display_point, text_layout_details)
14483                                .into(),
14484                        );
14485                        (display_point, goal)
14486                    })
14487                });
14488            }
14489        });
14490    }
14491
14492    pub fn select_enclosing_symbol(
14493        &mut self,
14494        _: &SelectEnclosingSymbol,
14495        window: &mut Window,
14496        cx: &mut Context<Self>,
14497    ) {
14498        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14499
14500        let buffer = self.buffer.read(cx).snapshot(cx);
14501        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14502
14503        fn update_selection(
14504            selection: &Selection<usize>,
14505            buffer_snap: &MultiBufferSnapshot,
14506        ) -> Option<Selection<usize>> {
14507            let cursor = selection.head();
14508            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14509            for symbol in symbols.iter().rev() {
14510                let start = symbol.range.start.to_offset(buffer_snap);
14511                let end = symbol.range.end.to_offset(buffer_snap);
14512                let new_range = start..end;
14513                if start < selection.start || end > selection.end {
14514                    return Some(Selection {
14515                        id: selection.id,
14516                        start: new_range.start,
14517                        end: new_range.end,
14518                        goal: SelectionGoal::None,
14519                        reversed: selection.reversed,
14520                    });
14521                }
14522            }
14523            None
14524        }
14525
14526        let mut selected_larger_symbol = false;
14527        let new_selections = old_selections
14528            .iter()
14529            .map(|selection| match update_selection(selection, &buffer) {
14530                Some(new_selection) => {
14531                    if new_selection.range() != selection.range() {
14532                        selected_larger_symbol = true;
14533                    }
14534                    new_selection
14535                }
14536                None => selection.clone(),
14537            })
14538            .collect::<Vec<_>>();
14539
14540        if selected_larger_symbol {
14541            self.change_selections(Default::default(), window, cx, |s| {
14542                s.select(new_selections);
14543            });
14544        }
14545    }
14546
14547    pub fn select_larger_syntax_node(
14548        &mut self,
14549        _: &SelectLargerSyntaxNode,
14550        window: &mut Window,
14551        cx: &mut Context<Self>,
14552    ) {
14553        let Some(visible_row_count) = self.visible_row_count() else {
14554            return;
14555        };
14556        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14557        if old_selections.is_empty() {
14558            return;
14559        }
14560
14561        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14562
14563        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14564        let buffer = self.buffer.read(cx).snapshot(cx);
14565
14566        let mut selected_larger_node = false;
14567        let mut new_selections = old_selections
14568            .iter()
14569            .map(|selection| {
14570                let old_range = selection.start..selection.end;
14571
14572                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14573                    // manually select word at selection
14574                    if ["string_content", "inline"].contains(&node.kind()) {
14575                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14576                        // ignore if word is already selected
14577                        if !word_range.is_empty() && old_range != word_range {
14578                            let (last_word_range, _) =
14579                                buffer.surrounding_word(old_range.end, false);
14580                            // only select word if start and end point belongs to same word
14581                            if word_range == last_word_range {
14582                                selected_larger_node = true;
14583                                return Selection {
14584                                    id: selection.id,
14585                                    start: word_range.start,
14586                                    end: word_range.end,
14587                                    goal: SelectionGoal::None,
14588                                    reversed: selection.reversed,
14589                                };
14590                            }
14591                        }
14592                    }
14593                }
14594
14595                let mut new_range = old_range.clone();
14596                while let Some((_node, containing_range)) =
14597                    buffer.syntax_ancestor(new_range.clone())
14598                {
14599                    new_range = match containing_range {
14600                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14601                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14602                    };
14603                    if !display_map.intersects_fold(new_range.start)
14604                        && !display_map.intersects_fold(new_range.end)
14605                    {
14606                        break;
14607                    }
14608                }
14609
14610                selected_larger_node |= new_range != old_range;
14611                Selection {
14612                    id: selection.id,
14613                    start: new_range.start,
14614                    end: new_range.end,
14615                    goal: SelectionGoal::None,
14616                    reversed: selection.reversed,
14617                }
14618            })
14619            .collect::<Vec<_>>();
14620
14621        if !selected_larger_node {
14622            return; // don't put this call in the history
14623        }
14624
14625        // scroll based on transformation done to the last selection created by the user
14626        let (last_old, last_new) = old_selections
14627            .last()
14628            .zip(new_selections.last().cloned())
14629            .expect("old_selections isn't empty");
14630
14631        // revert selection
14632        let is_selection_reversed = {
14633            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14634            new_selections.last_mut().expect("checked above").reversed =
14635                should_newest_selection_be_reversed;
14636            should_newest_selection_be_reversed
14637        };
14638
14639        if selected_larger_node {
14640            self.select_syntax_node_history.disable_clearing = true;
14641            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14642                s.select(new_selections.clone());
14643            });
14644            self.select_syntax_node_history.disable_clearing = false;
14645        }
14646
14647        let start_row = last_new.start.to_display_point(&display_map).row().0;
14648        let end_row = last_new.end.to_display_point(&display_map).row().0;
14649        let selection_height = end_row - start_row + 1;
14650        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14651
14652        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14653        let scroll_behavior = if fits_on_the_screen {
14654            self.request_autoscroll(Autoscroll::fit(), cx);
14655            SelectSyntaxNodeScrollBehavior::FitSelection
14656        } else if is_selection_reversed {
14657            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14658            SelectSyntaxNodeScrollBehavior::CursorTop
14659        } else {
14660            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14661            SelectSyntaxNodeScrollBehavior::CursorBottom
14662        };
14663
14664        self.select_syntax_node_history.push((
14665            old_selections,
14666            scroll_behavior,
14667            is_selection_reversed,
14668        ));
14669    }
14670
14671    pub fn select_smaller_syntax_node(
14672        &mut self,
14673        _: &SelectSmallerSyntaxNode,
14674        window: &mut Window,
14675        cx: &mut Context<Self>,
14676    ) {
14677        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14678
14679        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14680            self.select_syntax_node_history.pop()
14681        {
14682            if let Some(selection) = selections.last_mut() {
14683                selection.reversed = is_selection_reversed;
14684            }
14685
14686            self.select_syntax_node_history.disable_clearing = true;
14687            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14688                s.select(selections.to_vec());
14689            });
14690            self.select_syntax_node_history.disable_clearing = false;
14691
14692            match scroll_behavior {
14693                SelectSyntaxNodeScrollBehavior::CursorTop => {
14694                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14695                }
14696                SelectSyntaxNodeScrollBehavior::FitSelection => {
14697                    self.request_autoscroll(Autoscroll::fit(), cx);
14698                }
14699                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14700                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14701                }
14702            }
14703        }
14704    }
14705
14706    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14707        if !EditorSettings::get_global(cx).gutter.runnables {
14708            self.clear_tasks();
14709            return Task::ready(());
14710        }
14711        let project = self.project.as_ref().map(Entity::downgrade);
14712        let task_sources = self.lsp_task_sources(cx);
14713        let multi_buffer = self.buffer.downgrade();
14714        cx.spawn_in(window, async move |editor, cx| {
14715            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14716            let Some(project) = project.and_then(|p| p.upgrade()) else {
14717                return;
14718            };
14719            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14720                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14721            }) else {
14722                return;
14723            };
14724
14725            let hide_runnables = project
14726                .update(cx, |project, cx| {
14727                    // Do not display any test indicators in non-dev server remote projects.
14728                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14729                })
14730                .unwrap_or(true);
14731            if hide_runnables {
14732                return;
14733            }
14734            let new_rows =
14735                cx.background_spawn({
14736                    let snapshot = display_snapshot.clone();
14737                    async move {
14738                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14739                    }
14740                })
14741                    .await;
14742            let Ok(lsp_tasks) =
14743                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14744            else {
14745                return;
14746            };
14747            let lsp_tasks = lsp_tasks.await;
14748
14749            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14750                lsp_tasks
14751                    .into_iter()
14752                    .flat_map(|(kind, tasks)| {
14753                        tasks.into_iter().filter_map(move |(location, task)| {
14754                            Some((kind.clone(), location?, task))
14755                        })
14756                    })
14757                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14758                        let buffer = location.target.buffer;
14759                        let buffer_snapshot = buffer.read(cx).snapshot();
14760                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14761                            |(excerpt_id, snapshot, _)| {
14762                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14763                                    display_snapshot
14764                                        .buffer_snapshot
14765                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14766                                } else {
14767                                    None
14768                                }
14769                            },
14770                        );
14771                        if let Some(offset) = offset {
14772                            let task_buffer_range =
14773                                location.target.range.to_point(&buffer_snapshot);
14774                            let context_buffer_range =
14775                                task_buffer_range.to_offset(&buffer_snapshot);
14776                            let context_range = BufferOffset(context_buffer_range.start)
14777                                ..BufferOffset(context_buffer_range.end);
14778
14779                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14780                                .or_insert_with(|| RunnableTasks {
14781                                    templates: Vec::new(),
14782                                    offset,
14783                                    column: task_buffer_range.start.column,
14784                                    extra_variables: HashMap::default(),
14785                                    context_range,
14786                                })
14787                                .templates
14788                                .push((kind, task.original_task().clone()));
14789                        }
14790
14791                        acc
14792                    })
14793            }) else {
14794                return;
14795            };
14796
14797            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14798                buffer.language_settings(cx).tasks.prefer_lsp
14799            }) else {
14800                return;
14801            };
14802
14803            let rows = Self::runnable_rows(
14804                project,
14805                display_snapshot,
14806                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14807                new_rows,
14808                cx.clone(),
14809            )
14810            .await;
14811            editor
14812                .update(cx, |editor, _| {
14813                    editor.clear_tasks();
14814                    for (key, mut value) in rows {
14815                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14816                            value.templates.extend(lsp_tasks.templates);
14817                        }
14818
14819                        editor.insert_tasks(key, value);
14820                    }
14821                    for (key, value) in lsp_tasks_by_rows {
14822                        editor.insert_tasks(key, value);
14823                    }
14824                })
14825                .ok();
14826        })
14827    }
14828    fn fetch_runnable_ranges(
14829        snapshot: &DisplaySnapshot,
14830        range: Range<Anchor>,
14831    ) -> Vec<language::RunnableRange> {
14832        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14833    }
14834
14835    fn runnable_rows(
14836        project: Entity<Project>,
14837        snapshot: DisplaySnapshot,
14838        prefer_lsp: bool,
14839        runnable_ranges: Vec<RunnableRange>,
14840        cx: AsyncWindowContext,
14841    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14842        cx.spawn(async move |cx| {
14843            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14844            for mut runnable in runnable_ranges {
14845                let Some(tasks) = cx
14846                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14847                    .ok()
14848                else {
14849                    continue;
14850                };
14851                let mut tasks = tasks.await;
14852
14853                if prefer_lsp {
14854                    tasks.retain(|(task_kind, _)| {
14855                        !matches!(task_kind, TaskSourceKind::Language { .. })
14856                    });
14857                }
14858                if tasks.is_empty() {
14859                    continue;
14860                }
14861
14862                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14863                let Some(row) = snapshot
14864                    .buffer_snapshot
14865                    .buffer_line_for_row(MultiBufferRow(point.row))
14866                    .map(|(_, range)| range.start.row)
14867                else {
14868                    continue;
14869                };
14870
14871                let context_range =
14872                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14873                runnable_rows.push((
14874                    (runnable.buffer_id, row),
14875                    RunnableTasks {
14876                        templates: tasks,
14877                        offset: snapshot
14878                            .buffer_snapshot
14879                            .anchor_before(runnable.run_range.start),
14880                        context_range,
14881                        column: point.column,
14882                        extra_variables: runnable.extra_captures,
14883                    },
14884                ));
14885            }
14886            runnable_rows
14887        })
14888    }
14889
14890    fn templates_with_tags(
14891        project: &Entity<Project>,
14892        runnable: &mut Runnable,
14893        cx: &mut App,
14894    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14895        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14896            let (worktree_id, file) = project
14897                .buffer_for_id(runnable.buffer, cx)
14898                .and_then(|buffer| buffer.read(cx).file())
14899                .map(|file| (file.worktree_id(cx), file.clone()))
14900                .unzip();
14901
14902            (
14903                project.task_store().read(cx).task_inventory().cloned(),
14904                worktree_id,
14905                file,
14906            )
14907        });
14908
14909        let tags = mem::take(&mut runnable.tags);
14910        let language = runnable.language.clone();
14911        cx.spawn(async move |cx| {
14912            let mut templates_with_tags = Vec::new();
14913            if let Some(inventory) = inventory {
14914                for RunnableTag(tag) in tags {
14915                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14916                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14917                    }) else {
14918                        return templates_with_tags;
14919                    };
14920                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14921                        move |(_, template)| {
14922                            template.tags.iter().any(|source_tag| source_tag == &tag)
14923                        },
14924                    ));
14925                }
14926            }
14927            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14928
14929            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14930                // Strongest source wins; if we have worktree tag binding, prefer that to
14931                // global and language bindings;
14932                // if we have a global binding, prefer that to language binding.
14933                let first_mismatch = templates_with_tags
14934                    .iter()
14935                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14936                if let Some(index) = first_mismatch {
14937                    templates_with_tags.truncate(index);
14938                }
14939            }
14940
14941            templates_with_tags
14942        })
14943    }
14944
14945    pub fn move_to_enclosing_bracket(
14946        &mut self,
14947        _: &MoveToEnclosingBracket,
14948        window: &mut Window,
14949        cx: &mut Context<Self>,
14950    ) {
14951        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14952        self.change_selections(Default::default(), window, cx, |s| {
14953            s.move_offsets_with(|snapshot, selection| {
14954                let Some(enclosing_bracket_ranges) =
14955                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14956                else {
14957                    return;
14958                };
14959
14960                let mut best_length = usize::MAX;
14961                let mut best_inside = false;
14962                let mut best_in_bracket_range = false;
14963                let mut best_destination = None;
14964                for (open, close) in enclosing_bracket_ranges {
14965                    let close = close.to_inclusive();
14966                    let length = close.end() - open.start;
14967                    let inside = selection.start >= open.end && selection.end <= *close.start();
14968                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14969                        || close.contains(&selection.head());
14970
14971                    // If best is next to a bracket and current isn't, skip
14972                    if !in_bracket_range && best_in_bracket_range {
14973                        continue;
14974                    }
14975
14976                    // Prefer smaller lengths unless best is inside and current isn't
14977                    if length > best_length && (best_inside || !inside) {
14978                        continue;
14979                    }
14980
14981                    best_length = length;
14982                    best_inside = inside;
14983                    best_in_bracket_range = in_bracket_range;
14984                    best_destination = Some(
14985                        if close.contains(&selection.start) && close.contains(&selection.end) {
14986                            if inside { open.end } else { open.start }
14987                        } else if inside {
14988                            *close.start()
14989                        } else {
14990                            *close.end()
14991                        },
14992                    );
14993                }
14994
14995                if let Some(destination) = best_destination {
14996                    selection.collapse_to(destination, SelectionGoal::None);
14997                }
14998            })
14999        });
15000    }
15001
15002    pub fn undo_selection(
15003        &mut self,
15004        _: &UndoSelection,
15005        window: &mut Window,
15006        cx: &mut Context<Self>,
15007    ) {
15008        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15009        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15010            self.selection_history.mode = SelectionHistoryMode::Undoing;
15011            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15012                this.end_selection(window, cx);
15013                this.change_selections(
15014                    SelectionEffects::scroll(Autoscroll::newest()),
15015                    window,
15016                    cx,
15017                    |s| s.select_anchors(entry.selections.to_vec()),
15018                );
15019            });
15020            self.selection_history.mode = SelectionHistoryMode::Normal;
15021
15022            self.select_next_state = entry.select_next_state;
15023            self.select_prev_state = entry.select_prev_state;
15024            self.add_selections_state = entry.add_selections_state;
15025        }
15026    }
15027
15028    pub fn redo_selection(
15029        &mut self,
15030        _: &RedoSelection,
15031        window: &mut Window,
15032        cx: &mut Context<Self>,
15033    ) {
15034        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15035        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15036            self.selection_history.mode = SelectionHistoryMode::Redoing;
15037            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15038                this.end_selection(window, cx);
15039                this.change_selections(
15040                    SelectionEffects::scroll(Autoscroll::newest()),
15041                    window,
15042                    cx,
15043                    |s| s.select_anchors(entry.selections.to_vec()),
15044                );
15045            });
15046            self.selection_history.mode = SelectionHistoryMode::Normal;
15047
15048            self.select_next_state = entry.select_next_state;
15049            self.select_prev_state = entry.select_prev_state;
15050            self.add_selections_state = entry.add_selections_state;
15051        }
15052    }
15053
15054    pub fn expand_excerpts(
15055        &mut self,
15056        action: &ExpandExcerpts,
15057        _: &mut Window,
15058        cx: &mut Context<Self>,
15059    ) {
15060        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15061    }
15062
15063    pub fn expand_excerpts_down(
15064        &mut self,
15065        action: &ExpandExcerptsDown,
15066        _: &mut Window,
15067        cx: &mut Context<Self>,
15068    ) {
15069        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15070    }
15071
15072    pub fn expand_excerpts_up(
15073        &mut self,
15074        action: &ExpandExcerptsUp,
15075        _: &mut Window,
15076        cx: &mut Context<Self>,
15077    ) {
15078        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15079    }
15080
15081    pub fn expand_excerpts_for_direction(
15082        &mut self,
15083        lines: u32,
15084        direction: ExpandExcerptDirection,
15085
15086        cx: &mut Context<Self>,
15087    ) {
15088        let selections = self.selections.disjoint_anchors();
15089
15090        let lines = if lines == 0 {
15091            EditorSettings::get_global(cx).expand_excerpt_lines
15092        } else {
15093            lines
15094        };
15095
15096        self.buffer.update(cx, |buffer, cx| {
15097            let snapshot = buffer.snapshot(cx);
15098            let mut excerpt_ids = selections
15099                .iter()
15100                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15101                .collect::<Vec<_>>();
15102            excerpt_ids.sort();
15103            excerpt_ids.dedup();
15104            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15105        })
15106    }
15107
15108    pub fn expand_excerpt(
15109        &mut self,
15110        excerpt: ExcerptId,
15111        direction: ExpandExcerptDirection,
15112        window: &mut Window,
15113        cx: &mut Context<Self>,
15114    ) {
15115        let current_scroll_position = self.scroll_position(cx);
15116        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15117        let mut should_scroll_up = false;
15118
15119        if direction == ExpandExcerptDirection::Down {
15120            let multi_buffer = self.buffer.read(cx);
15121            let snapshot = multi_buffer.snapshot(cx);
15122            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
15123                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
15124                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
15125                        let buffer_snapshot = buffer.read(cx).snapshot();
15126                        let excerpt_end_row =
15127                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15128                        let last_row = buffer_snapshot.max_point().row;
15129                        let lines_below = last_row.saturating_sub(excerpt_end_row);
15130                        should_scroll_up = lines_below >= lines_to_expand;
15131                    }
15132                }
15133            }
15134        }
15135
15136        self.buffer.update(cx, |buffer, cx| {
15137            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15138        });
15139
15140        if should_scroll_up {
15141            let new_scroll_position =
15142                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15143            self.set_scroll_position(new_scroll_position, window, cx);
15144        }
15145    }
15146
15147    pub fn go_to_singleton_buffer_point(
15148        &mut self,
15149        point: Point,
15150        window: &mut Window,
15151        cx: &mut Context<Self>,
15152    ) {
15153        self.go_to_singleton_buffer_range(point..point, window, cx);
15154    }
15155
15156    pub fn go_to_singleton_buffer_range(
15157        &mut self,
15158        range: Range<Point>,
15159        window: &mut Window,
15160        cx: &mut Context<Self>,
15161    ) {
15162        let multibuffer = self.buffer().read(cx);
15163        let Some(buffer) = multibuffer.as_singleton() else {
15164            return;
15165        };
15166        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15167            return;
15168        };
15169        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15170            return;
15171        };
15172        self.change_selections(
15173            SelectionEffects::default().nav_history(true),
15174            window,
15175            cx,
15176            |s| s.select_anchor_ranges([start..end]),
15177        );
15178    }
15179
15180    pub fn go_to_diagnostic(
15181        &mut self,
15182        action: &GoToDiagnostic,
15183        window: &mut Window,
15184        cx: &mut Context<Self>,
15185    ) {
15186        if !self.diagnostics_enabled() {
15187            return;
15188        }
15189        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15190        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15191    }
15192
15193    pub fn go_to_prev_diagnostic(
15194        &mut self,
15195        action: &GoToPreviousDiagnostic,
15196        window: &mut Window,
15197        cx: &mut Context<Self>,
15198    ) {
15199        if !self.diagnostics_enabled() {
15200            return;
15201        }
15202        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15203        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15204    }
15205
15206    pub fn go_to_diagnostic_impl(
15207        &mut self,
15208        direction: Direction,
15209        severity: GoToDiagnosticSeverityFilter,
15210        window: &mut Window,
15211        cx: &mut Context<Self>,
15212    ) {
15213        let buffer = self.buffer.read(cx).snapshot(cx);
15214        let selection = self.selections.newest::<usize>(cx);
15215
15216        let mut active_group_id = None;
15217        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
15218            if active_group.active_range.start.to_offset(&buffer) == selection.start {
15219                active_group_id = Some(active_group.group_id);
15220            }
15221        }
15222
15223        fn filtered(
15224            snapshot: EditorSnapshot,
15225            severity: GoToDiagnosticSeverityFilter,
15226            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15227        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15228            diagnostics
15229                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15230                .filter(|entry| entry.range.start != entry.range.end)
15231                .filter(|entry| !entry.diagnostic.is_unnecessary)
15232                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15233        }
15234
15235        let snapshot = self.snapshot(window, cx);
15236        let before = filtered(
15237            snapshot.clone(),
15238            severity,
15239            buffer
15240                .diagnostics_in_range(0..selection.start)
15241                .filter(|entry| entry.range.start <= selection.start),
15242        );
15243        let after = filtered(
15244            snapshot,
15245            severity,
15246            buffer
15247                .diagnostics_in_range(selection.start..buffer.len())
15248                .filter(|entry| entry.range.start >= selection.start),
15249        );
15250
15251        let mut found: Option<DiagnosticEntry<usize>> = None;
15252        if direction == Direction::Prev {
15253            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15254            {
15255                for diagnostic in prev_diagnostics.into_iter().rev() {
15256                    if diagnostic.range.start != selection.start
15257                        || active_group_id
15258                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15259                    {
15260                        found = Some(diagnostic);
15261                        break 'outer;
15262                    }
15263                }
15264            }
15265        } else {
15266            for diagnostic in after.chain(before) {
15267                if diagnostic.range.start != selection.start
15268                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15269                {
15270                    found = Some(diagnostic);
15271                    break;
15272                }
15273            }
15274        }
15275        let Some(next_diagnostic) = found else {
15276            return;
15277        };
15278
15279        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
15280            return;
15281        };
15282        self.change_selections(Default::default(), window, cx, |s| {
15283            s.select_ranges(vec![
15284                next_diagnostic.range.start..next_diagnostic.range.start,
15285            ])
15286        });
15287        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15288        self.refresh_inline_completion(false, true, window, cx);
15289    }
15290
15291    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15292        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15293        let snapshot = self.snapshot(window, cx);
15294        let selection = self.selections.newest::<Point>(cx);
15295        self.go_to_hunk_before_or_after_position(
15296            &snapshot,
15297            selection.head(),
15298            Direction::Next,
15299            window,
15300            cx,
15301        );
15302    }
15303
15304    pub fn go_to_hunk_before_or_after_position(
15305        &mut self,
15306        snapshot: &EditorSnapshot,
15307        position: Point,
15308        direction: Direction,
15309        window: &mut Window,
15310        cx: &mut Context<Editor>,
15311    ) {
15312        let row = if direction == Direction::Next {
15313            self.hunk_after_position(snapshot, position)
15314                .map(|hunk| hunk.row_range.start)
15315        } else {
15316            self.hunk_before_position(snapshot, position)
15317        };
15318
15319        if let Some(row) = row {
15320            let destination = Point::new(row.0, 0);
15321            let autoscroll = Autoscroll::center();
15322
15323            self.unfold_ranges(&[destination..destination], false, false, cx);
15324            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15325                s.select_ranges([destination..destination]);
15326            });
15327        }
15328    }
15329
15330    fn hunk_after_position(
15331        &mut self,
15332        snapshot: &EditorSnapshot,
15333        position: Point,
15334    ) -> Option<MultiBufferDiffHunk> {
15335        snapshot
15336            .buffer_snapshot
15337            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15338            .find(|hunk| hunk.row_range.start.0 > position.row)
15339            .or_else(|| {
15340                snapshot
15341                    .buffer_snapshot
15342                    .diff_hunks_in_range(Point::zero()..position)
15343                    .find(|hunk| hunk.row_range.end.0 < position.row)
15344            })
15345    }
15346
15347    fn go_to_prev_hunk(
15348        &mut self,
15349        _: &GoToPreviousHunk,
15350        window: &mut Window,
15351        cx: &mut Context<Self>,
15352    ) {
15353        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15354        let snapshot = self.snapshot(window, cx);
15355        let selection = self.selections.newest::<Point>(cx);
15356        self.go_to_hunk_before_or_after_position(
15357            &snapshot,
15358            selection.head(),
15359            Direction::Prev,
15360            window,
15361            cx,
15362        );
15363    }
15364
15365    fn hunk_before_position(
15366        &mut self,
15367        snapshot: &EditorSnapshot,
15368        position: Point,
15369    ) -> Option<MultiBufferRow> {
15370        snapshot
15371            .buffer_snapshot
15372            .diff_hunk_before(position)
15373            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15374    }
15375
15376    fn go_to_next_change(
15377        &mut self,
15378        _: &GoToNextChange,
15379        window: &mut Window,
15380        cx: &mut Context<Self>,
15381    ) {
15382        if let Some(selections) = self
15383            .change_list
15384            .next_change(1, Direction::Next)
15385            .map(|s| s.to_vec())
15386        {
15387            self.change_selections(Default::default(), window, cx, |s| {
15388                let map = s.display_map();
15389                s.select_display_ranges(selections.iter().map(|a| {
15390                    let point = a.to_display_point(&map);
15391                    point..point
15392                }))
15393            })
15394        }
15395    }
15396
15397    fn go_to_previous_change(
15398        &mut self,
15399        _: &GoToPreviousChange,
15400        window: &mut Window,
15401        cx: &mut Context<Self>,
15402    ) {
15403        if let Some(selections) = self
15404            .change_list
15405            .next_change(1, Direction::Prev)
15406            .map(|s| s.to_vec())
15407        {
15408            self.change_selections(Default::default(), window, cx, |s| {
15409                let map = s.display_map();
15410                s.select_display_ranges(selections.iter().map(|a| {
15411                    let point = a.to_display_point(&map);
15412                    point..point
15413                }))
15414            })
15415        }
15416    }
15417
15418    fn go_to_line<T: 'static>(
15419        &mut self,
15420        position: Anchor,
15421        highlight_color: Option<Hsla>,
15422        window: &mut Window,
15423        cx: &mut Context<Self>,
15424    ) {
15425        let snapshot = self.snapshot(window, cx).display_snapshot;
15426        let position = position.to_point(&snapshot.buffer_snapshot);
15427        let start = snapshot
15428            .buffer_snapshot
15429            .clip_point(Point::new(position.row, 0), Bias::Left);
15430        let end = start + Point::new(1, 0);
15431        let start = snapshot.buffer_snapshot.anchor_before(start);
15432        let end = snapshot.buffer_snapshot.anchor_before(end);
15433
15434        self.highlight_rows::<T>(
15435            start..end,
15436            highlight_color
15437                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15438            Default::default(),
15439            cx,
15440        );
15441
15442        if self.buffer.read(cx).is_singleton() {
15443            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15444        }
15445    }
15446
15447    pub fn go_to_definition(
15448        &mut self,
15449        _: &GoToDefinition,
15450        window: &mut Window,
15451        cx: &mut Context<Self>,
15452    ) -> Task<Result<Navigated>> {
15453        let definition =
15454            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15455        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15456        cx.spawn_in(window, async move |editor, cx| {
15457            if definition.await? == Navigated::Yes {
15458                return Ok(Navigated::Yes);
15459            }
15460            match fallback_strategy {
15461                GoToDefinitionFallback::None => Ok(Navigated::No),
15462                GoToDefinitionFallback::FindAllReferences => {
15463                    match editor.update_in(cx, |editor, window, cx| {
15464                        editor.find_all_references(&FindAllReferences, window, cx)
15465                    })? {
15466                        Some(references) => references.await,
15467                        None => Ok(Navigated::No),
15468                    }
15469                }
15470            }
15471        })
15472    }
15473
15474    pub fn go_to_declaration(
15475        &mut self,
15476        _: &GoToDeclaration,
15477        window: &mut Window,
15478        cx: &mut Context<Self>,
15479    ) -> Task<Result<Navigated>> {
15480        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15481    }
15482
15483    pub fn go_to_declaration_split(
15484        &mut self,
15485        _: &GoToDeclaration,
15486        window: &mut Window,
15487        cx: &mut Context<Self>,
15488    ) -> Task<Result<Navigated>> {
15489        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15490    }
15491
15492    pub fn go_to_implementation(
15493        &mut self,
15494        _: &GoToImplementation,
15495        window: &mut Window,
15496        cx: &mut Context<Self>,
15497    ) -> Task<Result<Navigated>> {
15498        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15499    }
15500
15501    pub fn go_to_implementation_split(
15502        &mut self,
15503        _: &GoToImplementationSplit,
15504        window: &mut Window,
15505        cx: &mut Context<Self>,
15506    ) -> Task<Result<Navigated>> {
15507        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15508    }
15509
15510    pub fn go_to_type_definition(
15511        &mut self,
15512        _: &GoToTypeDefinition,
15513        window: &mut Window,
15514        cx: &mut Context<Self>,
15515    ) -> Task<Result<Navigated>> {
15516        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15517    }
15518
15519    pub fn go_to_definition_split(
15520        &mut self,
15521        _: &GoToDefinitionSplit,
15522        window: &mut Window,
15523        cx: &mut Context<Self>,
15524    ) -> Task<Result<Navigated>> {
15525        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15526    }
15527
15528    pub fn go_to_type_definition_split(
15529        &mut self,
15530        _: &GoToTypeDefinitionSplit,
15531        window: &mut Window,
15532        cx: &mut Context<Self>,
15533    ) -> Task<Result<Navigated>> {
15534        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15535    }
15536
15537    fn go_to_definition_of_kind(
15538        &mut self,
15539        kind: GotoDefinitionKind,
15540        split: bool,
15541        window: &mut Window,
15542        cx: &mut Context<Self>,
15543    ) -> Task<Result<Navigated>> {
15544        let Some(provider) = self.semantics_provider.clone() else {
15545            return Task::ready(Ok(Navigated::No));
15546        };
15547        let head = self.selections.newest::<usize>(cx).head();
15548        let buffer = self.buffer.read(cx);
15549        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
15550            text_anchor
15551        } else {
15552            return Task::ready(Ok(Navigated::No));
15553        };
15554
15555        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15556            return Task::ready(Ok(Navigated::No));
15557        };
15558
15559        cx.spawn_in(window, async move |editor, cx| {
15560            let definitions = definitions.await?;
15561            let navigated = editor
15562                .update_in(cx, |editor, window, cx| {
15563                    editor.navigate_to_hover_links(
15564                        Some(kind),
15565                        definitions
15566                            .into_iter()
15567                            .filter(|location| {
15568                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15569                            })
15570                            .map(HoverLink::Text)
15571                            .collect::<Vec<_>>(),
15572                        split,
15573                        window,
15574                        cx,
15575                    )
15576                })?
15577                .await?;
15578            anyhow::Ok(navigated)
15579        })
15580    }
15581
15582    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15583        let selection = self.selections.newest_anchor();
15584        let head = selection.head();
15585        let tail = selection.tail();
15586
15587        let Some((buffer, start_position)) =
15588            self.buffer.read(cx).text_anchor_for_position(head, cx)
15589        else {
15590            return;
15591        };
15592
15593        let end_position = if head != tail {
15594            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15595                return;
15596            };
15597            Some(pos)
15598        } else {
15599            None
15600        };
15601
15602        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15603            let url = if let Some(end_pos) = end_position {
15604                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15605            } else {
15606                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15607            };
15608
15609            if let Some(url) = url {
15610                editor.update(cx, |_, cx| {
15611                    cx.open_url(&url);
15612                })
15613            } else {
15614                Ok(())
15615            }
15616        });
15617
15618        url_finder.detach();
15619    }
15620
15621    pub fn open_selected_filename(
15622        &mut self,
15623        _: &OpenSelectedFilename,
15624        window: &mut Window,
15625        cx: &mut Context<Self>,
15626    ) {
15627        let Some(workspace) = self.workspace() else {
15628            return;
15629        };
15630
15631        let position = self.selections.newest_anchor().head();
15632
15633        let Some((buffer, buffer_position)) =
15634            self.buffer.read(cx).text_anchor_for_position(position, cx)
15635        else {
15636            return;
15637        };
15638
15639        let project = self.project.clone();
15640
15641        cx.spawn_in(window, async move |_, cx| {
15642            let result = find_file(&buffer, project, buffer_position, cx).await;
15643
15644            if let Some((_, path)) = result {
15645                workspace
15646                    .update_in(cx, |workspace, window, cx| {
15647                        workspace.open_resolved_path(path, window, cx)
15648                    })?
15649                    .await?;
15650            }
15651            anyhow::Ok(())
15652        })
15653        .detach();
15654    }
15655
15656    pub(crate) fn navigate_to_hover_links(
15657        &mut self,
15658        kind: Option<GotoDefinitionKind>,
15659        mut definitions: Vec<HoverLink>,
15660        split: bool,
15661        window: &mut Window,
15662        cx: &mut Context<Editor>,
15663    ) -> Task<Result<Navigated>> {
15664        // If there is one definition, just open it directly
15665        if definitions.len() == 1 {
15666            let definition = definitions.pop().unwrap();
15667
15668            enum TargetTaskResult {
15669                Location(Option<Location>),
15670                AlreadyNavigated,
15671            }
15672
15673            let target_task = match definition {
15674                HoverLink::Text(link) => {
15675                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
15676                }
15677                HoverLink::InlayHint(lsp_location, server_id) => {
15678                    let computation =
15679                        self.compute_target_location(lsp_location, server_id, window, cx);
15680                    cx.background_spawn(async move {
15681                        let location = computation.await?;
15682                        Ok(TargetTaskResult::Location(location))
15683                    })
15684                }
15685                HoverLink::Url(url) => {
15686                    cx.open_url(&url);
15687                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15688                }
15689                HoverLink::File(path) => {
15690                    if let Some(workspace) = self.workspace() {
15691                        cx.spawn_in(window, async move |_, cx| {
15692                            workspace
15693                                .update_in(cx, |workspace, window, cx| {
15694                                    workspace.open_resolved_path(path, window, cx)
15695                                })?
15696                                .await
15697                                .map(|_| TargetTaskResult::AlreadyNavigated)
15698                        })
15699                    } else {
15700                        Task::ready(Ok(TargetTaskResult::Location(None)))
15701                    }
15702                }
15703            };
15704            cx.spawn_in(window, async move |editor, cx| {
15705                let target = match target_task.await.context("target resolution task")? {
15706                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15707                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15708                    TargetTaskResult::Location(Some(target)) => target,
15709                };
15710
15711                editor.update_in(cx, |editor, window, cx| {
15712                    let Some(workspace) = editor.workspace() else {
15713                        return Navigated::No;
15714                    };
15715                    let pane = workspace.read(cx).active_pane().clone();
15716
15717                    let range = target.range.to_point(target.buffer.read(cx));
15718                    let range = editor.range_for_match(&range);
15719                    let range = collapse_multiline_range(range);
15720
15721                    if !split
15722                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15723                    {
15724                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15725                    } else {
15726                        window.defer(cx, move |window, cx| {
15727                            let target_editor: Entity<Self> =
15728                                workspace.update(cx, |workspace, cx| {
15729                                    let pane = if split {
15730                                        workspace.adjacent_pane(window, cx)
15731                                    } else {
15732                                        workspace.active_pane().clone()
15733                                    };
15734
15735                                    workspace.open_project_item(
15736                                        pane,
15737                                        target.buffer.clone(),
15738                                        true,
15739                                        true,
15740                                        window,
15741                                        cx,
15742                                    )
15743                                });
15744                            target_editor.update(cx, |target_editor, cx| {
15745                                // When selecting a definition in a different buffer, disable the nav history
15746                                // to avoid creating a history entry at the previous cursor location.
15747                                pane.update(cx, |pane, _| pane.disable_history());
15748                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15749                                pane.update(cx, |pane, _| pane.enable_history());
15750                            });
15751                        });
15752                    }
15753                    Navigated::Yes
15754                })
15755            })
15756        } else if !definitions.is_empty() {
15757            cx.spawn_in(window, async move |editor, cx| {
15758                let (title, location_tasks, workspace) = editor
15759                    .update_in(cx, |editor, window, cx| {
15760                        let tab_kind = match kind {
15761                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15762                            _ => "Definitions",
15763                        };
15764                        let title = definitions
15765                            .iter()
15766                            .find_map(|definition| match definition {
15767                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15768                                    let buffer = origin.buffer.read(cx);
15769                                    format!(
15770                                        "{} for {}",
15771                                        tab_kind,
15772                                        buffer
15773                                            .text_for_range(origin.range.clone())
15774                                            .collect::<String>()
15775                                    )
15776                                }),
15777                                HoverLink::InlayHint(_, _) => None,
15778                                HoverLink::Url(_) => None,
15779                                HoverLink::File(_) => None,
15780                            })
15781                            .unwrap_or(tab_kind.to_string());
15782                        let location_tasks = definitions
15783                            .into_iter()
15784                            .map(|definition| match definition {
15785                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15786                                HoverLink::InlayHint(lsp_location, server_id) => editor
15787                                    .compute_target_location(lsp_location, server_id, window, cx),
15788                                HoverLink::Url(_) => Task::ready(Ok(None)),
15789                                HoverLink::File(_) => Task::ready(Ok(None)),
15790                            })
15791                            .collect::<Vec<_>>();
15792                        (title, location_tasks, editor.workspace().clone())
15793                    })
15794                    .context("location tasks preparation")?;
15795
15796                let locations: Vec<Location> = future::join_all(location_tasks)
15797                    .await
15798                    .into_iter()
15799                    .filter_map(|location| location.transpose())
15800                    .collect::<Result<_>>()
15801                    .context("location tasks")?;
15802
15803                if locations.is_empty() {
15804                    return Ok(Navigated::No);
15805                }
15806
15807                let Some(workspace) = workspace else {
15808                    return Ok(Navigated::No);
15809                };
15810
15811                let opened = workspace
15812                    .update_in(cx, |workspace, window, cx| {
15813                        Self::open_locations_in_multibuffer(
15814                            workspace,
15815                            locations,
15816                            title,
15817                            split,
15818                            MultibufferSelectionMode::First,
15819                            window,
15820                            cx,
15821                        )
15822                    })
15823                    .ok();
15824
15825                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15826            })
15827        } else {
15828            Task::ready(Ok(Navigated::No))
15829        }
15830    }
15831
15832    fn compute_target_location(
15833        &self,
15834        lsp_location: lsp::Location,
15835        server_id: LanguageServerId,
15836        window: &mut Window,
15837        cx: &mut Context<Self>,
15838    ) -> Task<anyhow::Result<Option<Location>>> {
15839        let Some(project) = self.project.clone() else {
15840            return Task::ready(Ok(None));
15841        };
15842
15843        cx.spawn_in(window, async move |editor, cx| {
15844            let location_task = editor.update(cx, |_, cx| {
15845                project.update(cx, |project, cx| {
15846                    let language_server_name = project
15847                        .language_server_statuses(cx)
15848                        .find(|(id, _)| server_id == *id)
15849                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15850                    language_server_name.map(|language_server_name| {
15851                        project.open_local_buffer_via_lsp(
15852                            lsp_location.uri.clone(),
15853                            server_id,
15854                            language_server_name,
15855                            cx,
15856                        )
15857                    })
15858                })
15859            })?;
15860            let location = match location_task {
15861                Some(task) => Some({
15862                    let target_buffer_handle = task.await.context("open local buffer")?;
15863                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15864                        let target_start = target_buffer
15865                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15866                        let target_end = target_buffer
15867                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15868                        target_buffer.anchor_after(target_start)
15869                            ..target_buffer.anchor_before(target_end)
15870                    })?;
15871                    Location {
15872                        buffer: target_buffer_handle,
15873                        range,
15874                    }
15875                }),
15876                None => None,
15877            };
15878            Ok(location)
15879        })
15880    }
15881
15882    pub fn find_all_references(
15883        &mut self,
15884        _: &FindAllReferences,
15885        window: &mut Window,
15886        cx: &mut Context<Self>,
15887    ) -> Option<Task<Result<Navigated>>> {
15888        let selection = self.selections.newest::<usize>(cx);
15889        let multi_buffer = self.buffer.read(cx);
15890        let head = selection.head();
15891
15892        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15893        let head_anchor = multi_buffer_snapshot.anchor_at(
15894            head,
15895            if head < selection.tail() {
15896                Bias::Right
15897            } else {
15898                Bias::Left
15899            },
15900        );
15901
15902        match self
15903            .find_all_references_task_sources
15904            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15905        {
15906            Ok(_) => {
15907                log::info!(
15908                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15909                );
15910                return None;
15911            }
15912            Err(i) => {
15913                self.find_all_references_task_sources.insert(i, head_anchor);
15914            }
15915        }
15916
15917        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15918        let workspace = self.workspace()?;
15919        let project = workspace.read(cx).project().clone();
15920        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15921        Some(cx.spawn_in(window, async move |editor, cx| {
15922            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15923                if let Ok(i) = editor
15924                    .find_all_references_task_sources
15925                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15926                {
15927                    editor.find_all_references_task_sources.remove(i);
15928                }
15929            });
15930
15931            let locations = references.await?;
15932            if locations.is_empty() {
15933                return anyhow::Ok(Navigated::No);
15934            }
15935
15936            workspace.update_in(cx, |workspace, window, cx| {
15937                let title = locations
15938                    .first()
15939                    .as_ref()
15940                    .map(|location| {
15941                        let buffer = location.buffer.read(cx);
15942                        format!(
15943                            "References to `{}`",
15944                            buffer
15945                                .text_for_range(location.range.clone())
15946                                .collect::<String>()
15947                        )
15948                    })
15949                    .unwrap();
15950                Self::open_locations_in_multibuffer(
15951                    workspace,
15952                    locations,
15953                    title,
15954                    false,
15955                    MultibufferSelectionMode::First,
15956                    window,
15957                    cx,
15958                );
15959                Navigated::Yes
15960            })
15961        }))
15962    }
15963
15964    /// Opens a multibuffer with the given project locations in it
15965    pub fn open_locations_in_multibuffer(
15966        workspace: &mut Workspace,
15967        mut locations: Vec<Location>,
15968        title: String,
15969        split: bool,
15970        multibuffer_selection_mode: MultibufferSelectionMode,
15971        window: &mut Window,
15972        cx: &mut Context<Workspace>,
15973    ) {
15974        if locations.is_empty() {
15975            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
15976            return;
15977        }
15978
15979        // If there are multiple definitions, open them in a multibuffer
15980        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15981        let mut locations = locations.into_iter().peekable();
15982        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15983        let capability = workspace.project().read(cx).capability();
15984
15985        let excerpt_buffer = cx.new(|cx| {
15986            let mut multibuffer = MultiBuffer::new(capability);
15987            while let Some(location) = locations.next() {
15988                let buffer = location.buffer.read(cx);
15989                let mut ranges_for_buffer = Vec::new();
15990                let range = location.range.to_point(buffer);
15991                ranges_for_buffer.push(range.clone());
15992
15993                while let Some(next_location) = locations.peek() {
15994                    if next_location.buffer == location.buffer {
15995                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15996                        locations.next();
15997                    } else {
15998                        break;
15999                    }
16000                }
16001
16002                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16003                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16004                    PathKey::for_buffer(&location.buffer, cx),
16005                    location.buffer.clone(),
16006                    ranges_for_buffer,
16007                    DEFAULT_MULTIBUFFER_CONTEXT,
16008                    cx,
16009                );
16010                ranges.extend(new_ranges)
16011            }
16012
16013            multibuffer.with_title(title)
16014        });
16015
16016        let editor = cx.new(|cx| {
16017            Editor::for_multibuffer(
16018                excerpt_buffer,
16019                Some(workspace.project().clone()),
16020                window,
16021                cx,
16022            )
16023        });
16024        editor.update(cx, |editor, cx| {
16025            match multibuffer_selection_mode {
16026                MultibufferSelectionMode::First => {
16027                    if let Some(first_range) = ranges.first() {
16028                        editor.change_selections(
16029                            SelectionEffects::no_scroll(),
16030                            window,
16031                            cx,
16032                            |selections| {
16033                                selections.clear_disjoint();
16034                                selections
16035                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16036                            },
16037                        );
16038                    }
16039                    editor.highlight_background::<Self>(
16040                        &ranges,
16041                        |theme| theme.colors().editor_highlighted_line_background,
16042                        cx,
16043                    );
16044                }
16045                MultibufferSelectionMode::All => {
16046                    editor.change_selections(
16047                        SelectionEffects::no_scroll(),
16048                        window,
16049                        cx,
16050                        |selections| {
16051                            selections.clear_disjoint();
16052                            selections.select_anchor_ranges(ranges);
16053                        },
16054                    );
16055                }
16056            }
16057            editor.register_buffers_with_language_servers(cx);
16058        });
16059
16060        let item = Box::new(editor);
16061        let item_id = item.item_id();
16062
16063        if split {
16064            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
16065        } else {
16066            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16067                let (preview_item_id, preview_item_idx) =
16068                    workspace.active_pane().read_with(cx, |pane, _| {
16069                        (pane.preview_item_id(), pane.preview_item_idx())
16070                    });
16071
16072                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
16073
16074                if let Some(preview_item_id) = preview_item_id {
16075                    workspace.active_pane().update(cx, |pane, cx| {
16076                        pane.remove_item(preview_item_id, false, false, window, cx);
16077                    });
16078                }
16079            } else {
16080                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
16081            }
16082        }
16083        workspace.active_pane().update(cx, |pane, cx| {
16084            pane.set_preview_item_id(Some(item_id), cx);
16085        });
16086    }
16087
16088    pub fn rename(
16089        &mut self,
16090        _: &Rename,
16091        window: &mut Window,
16092        cx: &mut Context<Self>,
16093    ) -> Option<Task<Result<()>>> {
16094        use language::ToOffset as _;
16095
16096        let provider = self.semantics_provider.clone()?;
16097        let selection = self.selections.newest_anchor().clone();
16098        let (cursor_buffer, cursor_buffer_position) = self
16099            .buffer
16100            .read(cx)
16101            .text_anchor_for_position(selection.head(), cx)?;
16102        let (tail_buffer, cursor_buffer_position_end) = self
16103            .buffer
16104            .read(cx)
16105            .text_anchor_for_position(selection.tail(), cx)?;
16106        if tail_buffer != cursor_buffer {
16107            return None;
16108        }
16109
16110        let snapshot = cursor_buffer.read(cx).snapshot();
16111        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16112        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16113        let prepare_rename = provider
16114            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16115            .unwrap_or_else(|| Task::ready(Ok(None)));
16116        drop(snapshot);
16117
16118        Some(cx.spawn_in(window, async move |this, cx| {
16119            let rename_range = if let Some(range) = prepare_rename.await? {
16120                Some(range)
16121            } else {
16122                this.update(cx, |this, cx| {
16123                    let buffer = this.buffer.read(cx).snapshot(cx);
16124                    let mut buffer_highlights = this
16125                        .document_highlights_for_position(selection.head(), &buffer)
16126                        .filter(|highlight| {
16127                            highlight.start.excerpt_id == selection.head().excerpt_id
16128                                && highlight.end.excerpt_id == selection.head().excerpt_id
16129                        });
16130                    buffer_highlights
16131                        .next()
16132                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16133                })?
16134            };
16135            if let Some(rename_range) = rename_range {
16136                this.update_in(cx, |this, window, cx| {
16137                    let snapshot = cursor_buffer.read(cx).snapshot();
16138                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16139                    let cursor_offset_in_rename_range =
16140                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16141                    let cursor_offset_in_rename_range_end =
16142                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16143
16144                    this.take_rename(false, window, cx);
16145                    let buffer = this.buffer.read(cx).read(cx);
16146                    let cursor_offset = selection.head().to_offset(&buffer);
16147                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16148                    let rename_end = rename_start + rename_buffer_range.len();
16149                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16150                    let mut old_highlight_id = None;
16151                    let old_name: Arc<str> = buffer
16152                        .chunks(rename_start..rename_end, true)
16153                        .map(|chunk| {
16154                            if old_highlight_id.is_none() {
16155                                old_highlight_id = chunk.syntax_highlight_id;
16156                            }
16157                            chunk.text
16158                        })
16159                        .collect::<String>()
16160                        .into();
16161
16162                    drop(buffer);
16163
16164                    // Position the selection in the rename editor so that it matches the current selection.
16165                    this.show_local_selections = false;
16166                    let rename_editor = cx.new(|cx| {
16167                        let mut editor = Editor::single_line(window, cx);
16168                        editor.buffer.update(cx, |buffer, cx| {
16169                            buffer.edit([(0..0, old_name.clone())], None, cx)
16170                        });
16171                        let rename_selection_range = match cursor_offset_in_rename_range
16172                            .cmp(&cursor_offset_in_rename_range_end)
16173                        {
16174                            Ordering::Equal => {
16175                                editor.select_all(&SelectAll, window, cx);
16176                                return editor;
16177                            }
16178                            Ordering::Less => {
16179                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16180                            }
16181                            Ordering::Greater => {
16182                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16183                            }
16184                        };
16185                        if rename_selection_range.end > old_name.len() {
16186                            editor.select_all(&SelectAll, window, cx);
16187                        } else {
16188                            editor.change_selections(Default::default(), window, cx, |s| {
16189                                s.select_ranges([rename_selection_range]);
16190                            });
16191                        }
16192                        editor
16193                    });
16194                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16195                        if e == &EditorEvent::Focused {
16196                            cx.emit(EditorEvent::FocusedIn)
16197                        }
16198                    })
16199                    .detach();
16200
16201                    let write_highlights =
16202                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16203                    let read_highlights =
16204                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16205                    let ranges = write_highlights
16206                        .iter()
16207                        .flat_map(|(_, ranges)| ranges.iter())
16208                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16209                        .cloned()
16210                        .collect();
16211
16212                    this.highlight_text::<Rename>(
16213                        ranges,
16214                        HighlightStyle {
16215                            fade_out: Some(0.6),
16216                            ..Default::default()
16217                        },
16218                        cx,
16219                    );
16220                    let rename_focus_handle = rename_editor.focus_handle(cx);
16221                    window.focus(&rename_focus_handle);
16222                    let block_id = this.insert_blocks(
16223                        [BlockProperties {
16224                            style: BlockStyle::Flex,
16225                            placement: BlockPlacement::Below(range.start),
16226                            height: Some(1),
16227                            render: Arc::new({
16228                                let rename_editor = rename_editor.clone();
16229                                move |cx: &mut BlockContext| {
16230                                    let mut text_style = cx.editor_style.text.clone();
16231                                    if let Some(highlight_style) = old_highlight_id
16232                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16233                                    {
16234                                        text_style = text_style.highlight(highlight_style);
16235                                    }
16236                                    div()
16237                                        .block_mouse_except_scroll()
16238                                        .pl(cx.anchor_x)
16239                                        .child(EditorElement::new(
16240                                            &rename_editor,
16241                                            EditorStyle {
16242                                                background: cx.theme().system().transparent,
16243                                                local_player: cx.editor_style.local_player,
16244                                                text: text_style,
16245                                                scrollbar_width: cx.editor_style.scrollbar_width,
16246                                                syntax: cx.editor_style.syntax.clone(),
16247                                                status: cx.editor_style.status.clone(),
16248                                                inlay_hints_style: HighlightStyle {
16249                                                    font_weight: Some(FontWeight::BOLD),
16250                                                    ..make_inlay_hints_style(cx.app)
16251                                                },
16252                                                inline_completion_styles: make_suggestion_styles(
16253                                                    cx.app,
16254                                                ),
16255                                                ..EditorStyle::default()
16256                                            },
16257                                        ))
16258                                        .into_any_element()
16259                                }
16260                            }),
16261                            priority: 0,
16262                        }],
16263                        Some(Autoscroll::fit()),
16264                        cx,
16265                    )[0];
16266                    this.pending_rename = Some(RenameState {
16267                        range,
16268                        old_name,
16269                        editor: rename_editor,
16270                        block_id,
16271                    });
16272                })?;
16273            }
16274
16275            Ok(())
16276        }))
16277    }
16278
16279    pub fn confirm_rename(
16280        &mut self,
16281        _: &ConfirmRename,
16282        window: &mut Window,
16283        cx: &mut Context<Self>,
16284    ) -> Option<Task<Result<()>>> {
16285        let rename = self.take_rename(false, window, cx)?;
16286        let workspace = self.workspace()?.downgrade();
16287        let (buffer, start) = self
16288            .buffer
16289            .read(cx)
16290            .text_anchor_for_position(rename.range.start, cx)?;
16291        let (end_buffer, _) = self
16292            .buffer
16293            .read(cx)
16294            .text_anchor_for_position(rename.range.end, cx)?;
16295        if buffer != end_buffer {
16296            return None;
16297        }
16298
16299        let old_name = rename.old_name;
16300        let new_name = rename.editor.read(cx).text(cx);
16301
16302        let rename = self.semantics_provider.as_ref()?.perform_rename(
16303            &buffer,
16304            start,
16305            new_name.clone(),
16306            cx,
16307        )?;
16308
16309        Some(cx.spawn_in(window, async move |editor, cx| {
16310            let project_transaction = rename.await?;
16311            Self::open_project_transaction(
16312                &editor,
16313                workspace,
16314                project_transaction,
16315                format!("Rename: {}{}", old_name, new_name),
16316                cx,
16317            )
16318            .await?;
16319
16320            editor.update(cx, |editor, cx| {
16321                editor.refresh_document_highlights(cx);
16322            })?;
16323            Ok(())
16324        }))
16325    }
16326
16327    fn take_rename(
16328        &mut self,
16329        moving_cursor: bool,
16330        window: &mut Window,
16331        cx: &mut Context<Self>,
16332    ) -> Option<RenameState> {
16333        let rename = self.pending_rename.take()?;
16334        if rename.editor.focus_handle(cx).is_focused(window) {
16335            window.focus(&self.focus_handle);
16336        }
16337
16338        self.remove_blocks(
16339            [rename.block_id].into_iter().collect(),
16340            Some(Autoscroll::fit()),
16341            cx,
16342        );
16343        self.clear_highlights::<Rename>(cx);
16344        self.show_local_selections = true;
16345
16346        if moving_cursor {
16347            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16348                editor.selections.newest::<usize>(cx).head()
16349            });
16350
16351            // Update the selection to match the position of the selection inside
16352            // the rename editor.
16353            let snapshot = self.buffer.read(cx).read(cx);
16354            let rename_range = rename.range.to_offset(&snapshot);
16355            let cursor_in_editor = snapshot
16356                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16357                .min(rename_range.end);
16358            drop(snapshot);
16359
16360            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16361                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16362            });
16363        } else {
16364            self.refresh_document_highlights(cx);
16365        }
16366
16367        Some(rename)
16368    }
16369
16370    pub fn pending_rename(&self) -> Option<&RenameState> {
16371        self.pending_rename.as_ref()
16372    }
16373
16374    fn format(
16375        &mut self,
16376        _: &Format,
16377        window: &mut Window,
16378        cx: &mut Context<Self>,
16379    ) -> Option<Task<Result<()>>> {
16380        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16381
16382        let project = match &self.project {
16383            Some(project) => project.clone(),
16384            None => return None,
16385        };
16386
16387        Some(self.perform_format(
16388            project,
16389            FormatTrigger::Manual,
16390            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16391            window,
16392            cx,
16393        ))
16394    }
16395
16396    fn format_selections(
16397        &mut self,
16398        _: &FormatSelections,
16399        window: &mut Window,
16400        cx: &mut Context<Self>,
16401    ) -> Option<Task<Result<()>>> {
16402        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16403
16404        let project = match &self.project {
16405            Some(project) => project.clone(),
16406            None => return None,
16407        };
16408
16409        let ranges = self
16410            .selections
16411            .all_adjusted(cx)
16412            .into_iter()
16413            .map(|selection| selection.range())
16414            .collect_vec();
16415
16416        Some(self.perform_format(
16417            project,
16418            FormatTrigger::Manual,
16419            FormatTarget::Ranges(ranges),
16420            window,
16421            cx,
16422        ))
16423    }
16424
16425    fn perform_format(
16426        &mut self,
16427        project: Entity<Project>,
16428        trigger: FormatTrigger,
16429        target: FormatTarget,
16430        window: &mut Window,
16431        cx: &mut Context<Self>,
16432    ) -> Task<Result<()>> {
16433        let buffer = self.buffer.clone();
16434        let (buffers, target) = match target {
16435            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16436            FormatTarget::Ranges(selection_ranges) => {
16437                let multi_buffer = buffer.read(cx);
16438                let snapshot = multi_buffer.read(cx);
16439                let mut buffers = HashSet::default();
16440                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16441                    BTreeMap::new();
16442                for selection_range in selection_ranges {
16443                    for (buffer, buffer_range, _) in
16444                        snapshot.range_to_buffer_ranges(selection_range)
16445                    {
16446                        let buffer_id = buffer.remote_id();
16447                        let start = buffer.anchor_before(buffer_range.start);
16448                        let end = buffer.anchor_after(buffer_range.end);
16449                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16450                        buffer_id_to_ranges
16451                            .entry(buffer_id)
16452                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16453                            .or_insert_with(|| vec![start..end]);
16454                    }
16455                }
16456                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16457            }
16458        };
16459
16460        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16461        let selections_prev = transaction_id_prev
16462            .and_then(|transaction_id_prev| {
16463                // default to selections as they were after the last edit, if we have them,
16464                // instead of how they are now.
16465                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16466                // will take you back to where you made the last edit, instead of staying where you scrolled
16467                self.selection_history
16468                    .transaction(transaction_id_prev)
16469                    .map(|t| t.0.clone())
16470            })
16471            .unwrap_or_else(|| {
16472                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
16473                self.selections.disjoint_anchors()
16474            });
16475
16476        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16477        let format = project.update(cx, |project, cx| {
16478            project.format(buffers, target, true, trigger, cx)
16479        });
16480
16481        cx.spawn_in(window, async move |editor, cx| {
16482            let transaction = futures::select_biased! {
16483                transaction = format.log_err().fuse() => transaction,
16484                () = timeout => {
16485                    log::warn!("timed out waiting for formatting");
16486                    None
16487                }
16488            };
16489
16490            buffer
16491                .update(cx, |buffer, cx| {
16492                    if let Some(transaction) = transaction {
16493                        if !buffer.is_singleton() {
16494                            buffer.push_transaction(&transaction.0, cx);
16495                        }
16496                    }
16497                    cx.notify();
16498                })
16499                .ok();
16500
16501            if let Some(transaction_id_now) =
16502                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16503            {
16504                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16505                if has_new_transaction {
16506                    _ = editor.update(cx, |editor, _| {
16507                        editor
16508                            .selection_history
16509                            .insert_transaction(transaction_id_now, selections_prev);
16510                    });
16511                }
16512            }
16513
16514            Ok(())
16515        })
16516    }
16517
16518    fn organize_imports(
16519        &mut self,
16520        _: &OrganizeImports,
16521        window: &mut Window,
16522        cx: &mut Context<Self>,
16523    ) -> Option<Task<Result<()>>> {
16524        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16525        let project = match &self.project {
16526            Some(project) => project.clone(),
16527            None => return None,
16528        };
16529        Some(self.perform_code_action_kind(
16530            project,
16531            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16532            window,
16533            cx,
16534        ))
16535    }
16536
16537    fn perform_code_action_kind(
16538        &mut self,
16539        project: Entity<Project>,
16540        kind: CodeActionKind,
16541        window: &mut Window,
16542        cx: &mut Context<Self>,
16543    ) -> Task<Result<()>> {
16544        let buffer = self.buffer.clone();
16545        let buffers = buffer.read(cx).all_buffers();
16546        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16547        let apply_action = project.update(cx, |project, cx| {
16548            project.apply_code_action_kind(buffers, kind, true, cx)
16549        });
16550        cx.spawn_in(window, async move |_, cx| {
16551            let transaction = futures::select_biased! {
16552                () = timeout => {
16553                    log::warn!("timed out waiting for executing code action");
16554                    None
16555                }
16556                transaction = apply_action.log_err().fuse() => transaction,
16557            };
16558            buffer
16559                .update(cx, |buffer, cx| {
16560                    // check if we need this
16561                    if let Some(transaction) = transaction {
16562                        if !buffer.is_singleton() {
16563                            buffer.push_transaction(&transaction.0, cx);
16564                        }
16565                    }
16566                    cx.notify();
16567                })
16568                .ok();
16569            Ok(())
16570        })
16571    }
16572
16573    pub fn restart_language_server(
16574        &mut self,
16575        _: &RestartLanguageServer,
16576        _: &mut Window,
16577        cx: &mut Context<Self>,
16578    ) {
16579        if let Some(project) = self.project.clone() {
16580            self.buffer.update(cx, |multi_buffer, cx| {
16581                project.update(cx, |project, cx| {
16582                    project.restart_language_servers_for_buffers(
16583                        multi_buffer.all_buffers().into_iter().collect(),
16584                        HashSet::default(),
16585                        cx,
16586                    );
16587                });
16588            })
16589        }
16590    }
16591
16592    pub fn stop_language_server(
16593        &mut self,
16594        _: &StopLanguageServer,
16595        _: &mut Window,
16596        cx: &mut Context<Self>,
16597    ) {
16598        if let Some(project) = self.project.clone() {
16599            self.buffer.update(cx, |multi_buffer, cx| {
16600                project.update(cx, |project, cx| {
16601                    project.stop_language_servers_for_buffers(
16602                        multi_buffer.all_buffers().into_iter().collect(),
16603                        HashSet::default(),
16604                        cx,
16605                    );
16606                    cx.emit(project::Event::RefreshInlayHints);
16607                });
16608            });
16609        }
16610    }
16611
16612    fn cancel_language_server_work(
16613        workspace: &mut Workspace,
16614        _: &actions::CancelLanguageServerWork,
16615        _: &mut Window,
16616        cx: &mut Context<Workspace>,
16617    ) {
16618        let project = workspace.project();
16619        let buffers = workspace
16620            .active_item(cx)
16621            .and_then(|item| item.act_as::<Editor>(cx))
16622            .map_or(HashSet::default(), |editor| {
16623                editor.read(cx).buffer.read(cx).all_buffers()
16624            });
16625        project.update(cx, |project, cx| {
16626            project.cancel_language_server_work_for_buffers(buffers, cx);
16627        });
16628    }
16629
16630    fn show_character_palette(
16631        &mut self,
16632        _: &ShowCharacterPalette,
16633        window: &mut Window,
16634        _: &mut Context<Self>,
16635    ) {
16636        window.show_character_palette();
16637    }
16638
16639    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16640        if !self.diagnostics_enabled() {
16641            return;
16642        }
16643
16644        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16645            let buffer = self.buffer.read(cx).snapshot(cx);
16646            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16647            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16648            let is_valid = buffer
16649                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16650                .any(|entry| {
16651                    entry.diagnostic.is_primary
16652                        && !entry.range.is_empty()
16653                        && entry.range.start == primary_range_start
16654                        && entry.diagnostic.message == active_diagnostics.active_message
16655                });
16656
16657            if !is_valid {
16658                self.dismiss_diagnostics(cx);
16659            }
16660        }
16661    }
16662
16663    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16664        match &self.active_diagnostics {
16665            ActiveDiagnostic::Group(group) => Some(group),
16666            _ => None,
16667        }
16668    }
16669
16670    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16671        if !self.diagnostics_enabled() {
16672            return;
16673        }
16674        self.dismiss_diagnostics(cx);
16675        self.active_diagnostics = ActiveDiagnostic::All;
16676    }
16677
16678    fn activate_diagnostics(
16679        &mut self,
16680        buffer_id: BufferId,
16681        diagnostic: DiagnosticEntry<usize>,
16682        window: &mut Window,
16683        cx: &mut Context<Self>,
16684    ) {
16685        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16686            return;
16687        }
16688        self.dismiss_diagnostics(cx);
16689        let snapshot = self.snapshot(window, cx);
16690        let buffer = self.buffer.read(cx).snapshot(cx);
16691        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16692            return;
16693        };
16694
16695        let diagnostic_group = buffer
16696            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16697            .collect::<Vec<_>>();
16698
16699        let blocks =
16700            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16701
16702        let blocks = self.display_map.update(cx, |display_map, cx| {
16703            display_map.insert_blocks(blocks, cx).into_iter().collect()
16704        });
16705        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16706            active_range: buffer.anchor_before(diagnostic.range.start)
16707                ..buffer.anchor_after(diagnostic.range.end),
16708            active_message: diagnostic.diagnostic.message.clone(),
16709            group_id: diagnostic.diagnostic.group_id,
16710            blocks,
16711        });
16712        cx.notify();
16713    }
16714
16715    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16716        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16717            return;
16718        };
16719
16720        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16721        if let ActiveDiagnostic::Group(group) = prev {
16722            self.display_map.update(cx, |display_map, cx| {
16723                display_map.remove_blocks(group.blocks, cx);
16724            });
16725            cx.notify();
16726        }
16727    }
16728
16729    /// Disable inline diagnostics rendering for this editor.
16730    pub fn disable_inline_diagnostics(&mut self) {
16731        self.inline_diagnostics_enabled = false;
16732        self.inline_diagnostics_update = Task::ready(());
16733        self.inline_diagnostics.clear();
16734    }
16735
16736    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16737        self.diagnostics_enabled = false;
16738        self.dismiss_diagnostics(cx);
16739        self.inline_diagnostics_update = Task::ready(());
16740        self.inline_diagnostics.clear();
16741    }
16742
16743    pub fn diagnostics_enabled(&self) -> bool {
16744        self.diagnostics_enabled && self.mode.is_full()
16745    }
16746
16747    pub fn inline_diagnostics_enabled(&self) -> bool {
16748        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16749    }
16750
16751    pub fn show_inline_diagnostics(&self) -> bool {
16752        self.show_inline_diagnostics
16753    }
16754
16755    pub fn toggle_inline_diagnostics(
16756        &mut self,
16757        _: &ToggleInlineDiagnostics,
16758        window: &mut Window,
16759        cx: &mut Context<Editor>,
16760    ) {
16761        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16762        self.refresh_inline_diagnostics(false, window, cx);
16763    }
16764
16765    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16766        self.diagnostics_max_severity = severity;
16767        self.display_map.update(cx, |display_map, _| {
16768            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16769        });
16770    }
16771
16772    pub fn toggle_diagnostics(
16773        &mut self,
16774        _: &ToggleDiagnostics,
16775        window: &mut Window,
16776        cx: &mut Context<Editor>,
16777    ) {
16778        if !self.diagnostics_enabled() {
16779            return;
16780        }
16781
16782        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16783            EditorSettings::get_global(cx)
16784                .diagnostics_max_severity
16785                .filter(|severity| severity != &DiagnosticSeverity::Off)
16786                .unwrap_or(DiagnosticSeverity::Hint)
16787        } else {
16788            DiagnosticSeverity::Off
16789        };
16790        self.set_max_diagnostics_severity(new_severity, cx);
16791        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16792            self.active_diagnostics = ActiveDiagnostic::None;
16793            self.inline_diagnostics_update = Task::ready(());
16794            self.inline_diagnostics.clear();
16795        } else {
16796            self.refresh_inline_diagnostics(false, window, cx);
16797        }
16798
16799        cx.notify();
16800    }
16801
16802    pub fn toggle_minimap(
16803        &mut self,
16804        _: &ToggleMinimap,
16805        window: &mut Window,
16806        cx: &mut Context<Editor>,
16807    ) {
16808        if self.supports_minimap(cx) {
16809            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16810        }
16811    }
16812
16813    fn refresh_inline_diagnostics(
16814        &mut self,
16815        debounce: bool,
16816        window: &mut Window,
16817        cx: &mut Context<Self>,
16818    ) {
16819        let max_severity = ProjectSettings::get_global(cx)
16820            .diagnostics
16821            .inline
16822            .max_severity
16823            .unwrap_or(self.diagnostics_max_severity);
16824
16825        if !self.inline_diagnostics_enabled()
16826            || !self.show_inline_diagnostics
16827            || max_severity == DiagnosticSeverity::Off
16828        {
16829            self.inline_diagnostics_update = Task::ready(());
16830            self.inline_diagnostics.clear();
16831            return;
16832        }
16833
16834        let debounce_ms = ProjectSettings::get_global(cx)
16835            .diagnostics
16836            .inline
16837            .update_debounce_ms;
16838        let debounce = if debounce && debounce_ms > 0 {
16839            Some(Duration::from_millis(debounce_ms))
16840        } else {
16841            None
16842        };
16843        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16844            if let Some(debounce) = debounce {
16845                cx.background_executor().timer(debounce).await;
16846            }
16847            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16848                editor
16849                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16850                    .ok()
16851            }) else {
16852                return;
16853            };
16854
16855            let new_inline_diagnostics = cx
16856                .background_spawn(async move {
16857                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16858                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16859                        let message = diagnostic_entry
16860                            .diagnostic
16861                            .message
16862                            .split_once('\n')
16863                            .map(|(line, _)| line)
16864                            .map(SharedString::new)
16865                            .unwrap_or_else(|| {
16866                                SharedString::from(diagnostic_entry.diagnostic.message)
16867                            });
16868                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16869                        let (Ok(i) | Err(i)) = inline_diagnostics
16870                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16871                        inline_diagnostics.insert(
16872                            i,
16873                            (
16874                                start_anchor,
16875                                InlineDiagnostic {
16876                                    message,
16877                                    group_id: diagnostic_entry.diagnostic.group_id,
16878                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16879                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16880                                    severity: diagnostic_entry.diagnostic.severity,
16881                                },
16882                            ),
16883                        );
16884                    }
16885                    inline_diagnostics
16886                })
16887                .await;
16888
16889            editor
16890                .update(cx, |editor, cx| {
16891                    editor.inline_diagnostics = new_inline_diagnostics;
16892                    cx.notify();
16893                })
16894                .ok();
16895        });
16896    }
16897
16898    fn pull_diagnostics(
16899        &mut self,
16900        buffer_id: Option<BufferId>,
16901        window: &Window,
16902        cx: &mut Context<Self>,
16903    ) -> Option<()> {
16904        if !self.mode().is_full() {
16905            return None;
16906        }
16907        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16908            .diagnostics
16909            .lsp_pull_diagnostics;
16910        if !pull_diagnostics_settings.enabled {
16911            return None;
16912        }
16913        let project = self.project.as_ref()?.downgrade();
16914        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16915        let mut buffers = self.buffer.read(cx).all_buffers();
16916        if let Some(buffer_id) = buffer_id {
16917            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16918        }
16919
16920        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16921            cx.background_executor().timer(debounce).await;
16922
16923            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16924                buffers
16925                    .into_iter()
16926                    .filter_map(|buffer| {
16927                        project
16928                            .update(cx, |project, cx| {
16929                                project.lsp_store().update(cx, |lsp_store, cx| {
16930                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
16931                                })
16932                            })
16933                            .ok()
16934                    })
16935                    .collect::<FuturesUnordered<_>>()
16936            }) else {
16937                return;
16938            };
16939
16940            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16941                match pull_task {
16942                    Ok(()) => {
16943                        if editor
16944                            .update_in(cx, |editor, window, cx| {
16945                                editor.update_diagnostics_state(window, cx);
16946                            })
16947                            .is_err()
16948                        {
16949                            return;
16950                        }
16951                    }
16952                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16953                }
16954            }
16955        });
16956
16957        Some(())
16958    }
16959
16960    pub fn set_selections_from_remote(
16961        &mut self,
16962        selections: Vec<Selection<Anchor>>,
16963        pending_selection: Option<Selection<Anchor>>,
16964        window: &mut Window,
16965        cx: &mut Context<Self>,
16966    ) {
16967        let old_cursor_position = self.selections.newest_anchor().head();
16968        self.selections.change_with(cx, |s| {
16969            s.select_anchors(selections);
16970            if let Some(pending_selection) = pending_selection {
16971                s.set_pending(pending_selection, SelectMode::Character);
16972            } else {
16973                s.clear_pending();
16974            }
16975        });
16976        self.selections_did_change(
16977            false,
16978            &old_cursor_position,
16979            SelectionEffects::default(),
16980            window,
16981            cx,
16982        );
16983    }
16984
16985    pub fn transact(
16986        &mut self,
16987        window: &mut Window,
16988        cx: &mut Context<Self>,
16989        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16990    ) -> Option<TransactionId> {
16991        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16992            this.start_transaction_at(Instant::now(), window, cx);
16993            update(this, window, cx);
16994            this.end_transaction_at(Instant::now(), cx)
16995        })
16996    }
16997
16998    pub fn start_transaction_at(
16999        &mut self,
17000        now: Instant,
17001        window: &mut Window,
17002        cx: &mut Context<Self>,
17003    ) -> Option<TransactionId> {
17004        self.end_selection(window, cx);
17005        if let Some(tx_id) = self
17006            .buffer
17007            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17008        {
17009            self.selection_history
17010                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17011            cx.emit(EditorEvent::TransactionBegun {
17012                transaction_id: tx_id,
17013            });
17014            Some(tx_id)
17015        } else {
17016            None
17017        }
17018    }
17019
17020    pub fn end_transaction_at(
17021        &mut self,
17022        now: Instant,
17023        cx: &mut Context<Self>,
17024    ) -> Option<TransactionId> {
17025        if let Some(transaction_id) = self
17026            .buffer
17027            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17028        {
17029            if let Some((_, end_selections)) =
17030                self.selection_history.transaction_mut(transaction_id)
17031            {
17032                *end_selections = Some(self.selections.disjoint_anchors());
17033            } else {
17034                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17035            }
17036
17037            cx.emit(EditorEvent::Edited { transaction_id });
17038            Some(transaction_id)
17039        } else {
17040            None
17041        }
17042    }
17043
17044    pub fn modify_transaction_selection_history(
17045        &mut self,
17046        transaction_id: TransactionId,
17047        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17048    ) -> bool {
17049        self.selection_history
17050            .transaction_mut(transaction_id)
17051            .map(modify)
17052            .is_some()
17053    }
17054
17055    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17056        if self.selection_mark_mode {
17057            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17058                s.move_with(|_, sel| {
17059                    sel.collapse_to(sel.head(), SelectionGoal::None);
17060                });
17061            })
17062        }
17063        self.selection_mark_mode = true;
17064        cx.notify();
17065    }
17066
17067    pub fn swap_selection_ends(
17068        &mut self,
17069        _: &actions::SwapSelectionEnds,
17070        window: &mut Window,
17071        cx: &mut Context<Self>,
17072    ) {
17073        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17074            s.move_with(|_, sel| {
17075                if sel.start != sel.end {
17076                    sel.reversed = !sel.reversed
17077                }
17078            });
17079        });
17080        self.request_autoscroll(Autoscroll::newest(), cx);
17081        cx.notify();
17082    }
17083
17084    pub fn toggle_focus(
17085        workspace: &mut Workspace,
17086        _: &actions::ToggleFocus,
17087        window: &mut Window,
17088        cx: &mut Context<Workspace>,
17089    ) {
17090        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17091            return;
17092        };
17093        workspace.activate_item(&item, true, true, window, cx);
17094    }
17095
17096    pub fn toggle_fold(
17097        &mut self,
17098        _: &actions::ToggleFold,
17099        window: &mut Window,
17100        cx: &mut Context<Self>,
17101    ) {
17102        if self.is_singleton(cx) {
17103            let selection = self.selections.newest::<Point>(cx);
17104
17105            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17106            let range = if selection.is_empty() {
17107                let point = selection.head().to_display_point(&display_map);
17108                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17109                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17110                    .to_point(&display_map);
17111                start..end
17112            } else {
17113                selection.range()
17114            };
17115            if display_map.folds_in_range(range).next().is_some() {
17116                self.unfold_lines(&Default::default(), window, cx)
17117            } else {
17118                self.fold(&Default::default(), window, cx)
17119            }
17120        } else {
17121            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17122            let buffer_ids: HashSet<_> = self
17123                .selections
17124                .disjoint_anchor_ranges()
17125                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17126                .collect();
17127
17128            let should_unfold = buffer_ids
17129                .iter()
17130                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17131
17132            for buffer_id in buffer_ids {
17133                if should_unfold {
17134                    self.unfold_buffer(buffer_id, cx);
17135                } else {
17136                    self.fold_buffer(buffer_id, cx);
17137                }
17138            }
17139        }
17140    }
17141
17142    pub fn toggle_fold_recursive(
17143        &mut self,
17144        _: &actions::ToggleFoldRecursive,
17145        window: &mut Window,
17146        cx: &mut Context<Self>,
17147    ) {
17148        let selection = self.selections.newest::<Point>(cx);
17149
17150        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17151        let range = if selection.is_empty() {
17152            let point = selection.head().to_display_point(&display_map);
17153            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17154            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17155                .to_point(&display_map);
17156            start..end
17157        } else {
17158            selection.range()
17159        };
17160        if display_map.folds_in_range(range).next().is_some() {
17161            self.unfold_recursive(&Default::default(), window, cx)
17162        } else {
17163            self.fold_recursive(&Default::default(), window, cx)
17164        }
17165    }
17166
17167    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17168        if self.is_singleton(cx) {
17169            let mut to_fold = Vec::new();
17170            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17171            let selections = self.selections.all_adjusted(cx);
17172
17173            for selection in selections {
17174                let range = selection.range().sorted();
17175                let buffer_start_row = range.start.row;
17176
17177                if range.start.row != range.end.row {
17178                    let mut found = false;
17179                    let mut row = range.start.row;
17180                    while row <= range.end.row {
17181                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17182                        {
17183                            found = true;
17184                            row = crease.range().end.row + 1;
17185                            to_fold.push(crease);
17186                        } else {
17187                            row += 1
17188                        }
17189                    }
17190                    if found {
17191                        continue;
17192                    }
17193                }
17194
17195                for row in (0..=range.start.row).rev() {
17196                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17197                        if crease.range().end.row >= buffer_start_row {
17198                            to_fold.push(crease);
17199                            if row <= range.start.row {
17200                                break;
17201                            }
17202                        }
17203                    }
17204                }
17205            }
17206
17207            self.fold_creases(to_fold, true, window, cx);
17208        } else {
17209            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17210            let buffer_ids = self
17211                .selections
17212                .disjoint_anchor_ranges()
17213                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17214                .collect::<HashSet<_>>();
17215            for buffer_id in buffer_ids {
17216                self.fold_buffer(buffer_id, cx);
17217            }
17218        }
17219    }
17220
17221    pub fn toggle_fold_all(
17222        &mut self,
17223        _: &actions::ToggleFoldAll,
17224        window: &mut Window,
17225        cx: &mut Context<Self>,
17226    ) {
17227        if self.buffer.read(cx).is_singleton() {
17228            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17229            let has_folds = display_map
17230                .folds_in_range(0..display_map.buffer_snapshot.len())
17231                .next()
17232                .is_some();
17233
17234            if has_folds {
17235                self.unfold_all(&actions::UnfoldAll, window, cx);
17236            } else {
17237                self.fold_all(&actions::FoldAll, window, cx);
17238            }
17239        } else {
17240            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17241            let should_unfold = buffer_ids
17242                .iter()
17243                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17244
17245            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17246                editor
17247                    .update_in(cx, |editor, _, cx| {
17248                        for buffer_id in buffer_ids {
17249                            if should_unfold {
17250                                editor.unfold_buffer(buffer_id, cx);
17251                            } else {
17252                                editor.fold_buffer(buffer_id, cx);
17253                            }
17254                        }
17255                    })
17256                    .ok();
17257            });
17258        }
17259    }
17260
17261    fn fold_at_level(
17262        &mut self,
17263        fold_at: &FoldAtLevel,
17264        window: &mut Window,
17265        cx: &mut Context<Self>,
17266    ) {
17267        if !self.buffer.read(cx).is_singleton() {
17268            return;
17269        }
17270
17271        let fold_at_level = fold_at.0;
17272        let snapshot = self.buffer.read(cx).snapshot(cx);
17273        let mut to_fold = Vec::new();
17274        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17275
17276        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17277            while start_row < end_row {
17278                match self
17279                    .snapshot(window, cx)
17280                    .crease_for_buffer_row(MultiBufferRow(start_row))
17281                {
17282                    Some(crease) => {
17283                        let nested_start_row = crease.range().start.row + 1;
17284                        let nested_end_row = crease.range().end.row;
17285
17286                        if current_level < fold_at_level {
17287                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17288                        } else if current_level == fold_at_level {
17289                            to_fold.push(crease);
17290                        }
17291
17292                        start_row = nested_end_row + 1;
17293                    }
17294                    None => start_row += 1,
17295                }
17296            }
17297        }
17298
17299        self.fold_creases(to_fold, true, window, cx);
17300    }
17301
17302    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17303        if self.buffer.read(cx).is_singleton() {
17304            let mut fold_ranges = Vec::new();
17305            let snapshot = self.buffer.read(cx).snapshot(cx);
17306
17307            for row in 0..snapshot.max_row().0 {
17308                if let Some(foldable_range) = self
17309                    .snapshot(window, cx)
17310                    .crease_for_buffer_row(MultiBufferRow(row))
17311                {
17312                    fold_ranges.push(foldable_range);
17313                }
17314            }
17315
17316            self.fold_creases(fold_ranges, true, window, cx);
17317        } else {
17318            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17319                editor
17320                    .update_in(cx, |editor, _, cx| {
17321                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17322                            editor.fold_buffer(buffer_id, cx);
17323                        }
17324                    })
17325                    .ok();
17326            });
17327        }
17328    }
17329
17330    pub fn fold_function_bodies(
17331        &mut self,
17332        _: &actions::FoldFunctionBodies,
17333        window: &mut Window,
17334        cx: &mut Context<Self>,
17335    ) {
17336        let snapshot = self.buffer.read(cx).snapshot(cx);
17337
17338        let ranges = snapshot
17339            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17340            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17341            .collect::<Vec<_>>();
17342
17343        let creases = ranges
17344            .into_iter()
17345            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17346            .collect();
17347
17348        self.fold_creases(creases, true, window, cx);
17349    }
17350
17351    pub fn fold_recursive(
17352        &mut self,
17353        _: &actions::FoldRecursive,
17354        window: &mut Window,
17355        cx: &mut Context<Self>,
17356    ) {
17357        let mut to_fold = Vec::new();
17358        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17359        let selections = self.selections.all_adjusted(cx);
17360
17361        for selection in selections {
17362            let range = selection.range().sorted();
17363            let buffer_start_row = range.start.row;
17364
17365            if range.start.row != range.end.row {
17366                let mut found = false;
17367                for row in range.start.row..=range.end.row {
17368                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17369                        found = true;
17370                        to_fold.push(crease);
17371                    }
17372                }
17373                if found {
17374                    continue;
17375                }
17376            }
17377
17378            for row in (0..=range.start.row).rev() {
17379                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17380                    if crease.range().end.row >= buffer_start_row {
17381                        to_fold.push(crease);
17382                    } else {
17383                        break;
17384                    }
17385                }
17386            }
17387        }
17388
17389        self.fold_creases(to_fold, true, window, cx);
17390    }
17391
17392    pub fn fold_at(
17393        &mut self,
17394        buffer_row: MultiBufferRow,
17395        window: &mut Window,
17396        cx: &mut Context<Self>,
17397    ) {
17398        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17399
17400        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17401            let autoscroll = self
17402                .selections
17403                .all::<Point>(cx)
17404                .iter()
17405                .any(|selection| crease.range().overlaps(&selection.range()));
17406
17407            self.fold_creases(vec![crease], autoscroll, window, cx);
17408        }
17409    }
17410
17411    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17412        if self.is_singleton(cx) {
17413            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17414            let buffer = &display_map.buffer_snapshot;
17415            let selections = self.selections.all::<Point>(cx);
17416            let ranges = selections
17417                .iter()
17418                .map(|s| {
17419                    let range = s.display_range(&display_map).sorted();
17420                    let mut start = range.start.to_point(&display_map);
17421                    let mut end = range.end.to_point(&display_map);
17422                    start.column = 0;
17423                    end.column = buffer.line_len(MultiBufferRow(end.row));
17424                    start..end
17425                })
17426                .collect::<Vec<_>>();
17427
17428            self.unfold_ranges(&ranges, true, true, cx);
17429        } else {
17430            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17431            let buffer_ids = self
17432                .selections
17433                .disjoint_anchor_ranges()
17434                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17435                .collect::<HashSet<_>>();
17436            for buffer_id in buffer_ids {
17437                self.unfold_buffer(buffer_id, cx);
17438            }
17439        }
17440    }
17441
17442    pub fn unfold_recursive(
17443        &mut self,
17444        _: &UnfoldRecursive,
17445        _window: &mut Window,
17446        cx: &mut Context<Self>,
17447    ) {
17448        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17449        let selections = self.selections.all::<Point>(cx);
17450        let ranges = selections
17451            .iter()
17452            .map(|s| {
17453                let mut range = s.display_range(&display_map).sorted();
17454                *range.start.column_mut() = 0;
17455                *range.end.column_mut() = display_map.line_len(range.end.row());
17456                let start = range.start.to_point(&display_map);
17457                let end = range.end.to_point(&display_map);
17458                start..end
17459            })
17460            .collect::<Vec<_>>();
17461
17462        self.unfold_ranges(&ranges, true, true, cx);
17463    }
17464
17465    pub fn unfold_at(
17466        &mut self,
17467        buffer_row: MultiBufferRow,
17468        _window: &mut Window,
17469        cx: &mut Context<Self>,
17470    ) {
17471        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17472
17473        let intersection_range = Point::new(buffer_row.0, 0)
17474            ..Point::new(
17475                buffer_row.0,
17476                display_map.buffer_snapshot.line_len(buffer_row),
17477            );
17478
17479        let autoscroll = self
17480            .selections
17481            .all::<Point>(cx)
17482            .iter()
17483            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17484
17485        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17486    }
17487
17488    pub fn unfold_all(
17489        &mut self,
17490        _: &actions::UnfoldAll,
17491        _window: &mut Window,
17492        cx: &mut Context<Self>,
17493    ) {
17494        if self.buffer.read(cx).is_singleton() {
17495            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17496            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17497        } else {
17498            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17499                editor
17500                    .update(cx, |editor, cx| {
17501                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17502                            editor.unfold_buffer(buffer_id, cx);
17503                        }
17504                    })
17505                    .ok();
17506            });
17507        }
17508    }
17509
17510    pub fn fold_selected_ranges(
17511        &mut self,
17512        _: &FoldSelectedRanges,
17513        window: &mut Window,
17514        cx: &mut Context<Self>,
17515    ) {
17516        let selections = self.selections.all_adjusted(cx);
17517        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17518        let ranges = selections
17519            .into_iter()
17520            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17521            .collect::<Vec<_>>();
17522        self.fold_creases(ranges, true, window, cx);
17523    }
17524
17525    pub fn fold_ranges<T: ToOffset + Clone>(
17526        &mut self,
17527        ranges: Vec<Range<T>>,
17528        auto_scroll: bool,
17529        window: &mut Window,
17530        cx: &mut Context<Self>,
17531    ) {
17532        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17533        let ranges = ranges
17534            .into_iter()
17535            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17536            .collect::<Vec<_>>();
17537        self.fold_creases(ranges, auto_scroll, window, cx);
17538    }
17539
17540    pub fn fold_creases<T: ToOffset + Clone>(
17541        &mut self,
17542        creases: Vec<Crease<T>>,
17543        auto_scroll: bool,
17544        _window: &mut Window,
17545        cx: &mut Context<Self>,
17546    ) {
17547        if creases.is_empty() {
17548            return;
17549        }
17550
17551        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17552
17553        if auto_scroll {
17554            self.request_autoscroll(Autoscroll::fit(), cx);
17555        }
17556
17557        cx.notify();
17558
17559        self.scrollbar_marker_state.dirty = true;
17560        self.folds_did_change(cx);
17561    }
17562
17563    /// Removes any folds whose ranges intersect any of the given ranges.
17564    pub fn unfold_ranges<T: ToOffset + Clone>(
17565        &mut self,
17566        ranges: &[Range<T>],
17567        inclusive: bool,
17568        auto_scroll: bool,
17569        cx: &mut Context<Self>,
17570    ) {
17571        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17572            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17573        });
17574        self.folds_did_change(cx);
17575    }
17576
17577    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17578        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17579            return;
17580        }
17581        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17582        self.display_map.update(cx, |display_map, cx| {
17583            display_map.fold_buffers([buffer_id], cx)
17584        });
17585        cx.emit(EditorEvent::BufferFoldToggled {
17586            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17587            folded: true,
17588        });
17589        cx.notify();
17590    }
17591
17592    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17593        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17594            return;
17595        }
17596        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17597        self.display_map.update(cx, |display_map, cx| {
17598            display_map.unfold_buffers([buffer_id], cx);
17599        });
17600        cx.emit(EditorEvent::BufferFoldToggled {
17601            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17602            folded: false,
17603        });
17604        cx.notify();
17605    }
17606
17607    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17608        self.display_map.read(cx).is_buffer_folded(buffer)
17609    }
17610
17611    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17612        self.display_map.read(cx).folded_buffers()
17613    }
17614
17615    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17616        self.display_map.update(cx, |display_map, cx| {
17617            display_map.disable_header_for_buffer(buffer_id, cx);
17618        });
17619        cx.notify();
17620    }
17621
17622    /// Removes any folds with the given ranges.
17623    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17624        &mut self,
17625        ranges: &[Range<T>],
17626        type_id: TypeId,
17627        auto_scroll: bool,
17628        cx: &mut Context<Self>,
17629    ) {
17630        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17631            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17632        });
17633        self.folds_did_change(cx);
17634    }
17635
17636    fn remove_folds_with<T: ToOffset + Clone>(
17637        &mut self,
17638        ranges: &[Range<T>],
17639        auto_scroll: bool,
17640        cx: &mut Context<Self>,
17641        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17642    ) {
17643        if ranges.is_empty() {
17644            return;
17645        }
17646
17647        let mut buffers_affected = HashSet::default();
17648        let multi_buffer = self.buffer().read(cx);
17649        for range in ranges {
17650            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17651                buffers_affected.insert(buffer.read(cx).remote_id());
17652            };
17653        }
17654
17655        self.display_map.update(cx, update);
17656
17657        if auto_scroll {
17658            self.request_autoscroll(Autoscroll::fit(), cx);
17659        }
17660
17661        cx.notify();
17662        self.scrollbar_marker_state.dirty = true;
17663        self.active_indent_guides_state.dirty = true;
17664    }
17665
17666    pub fn update_renderer_widths(
17667        &mut self,
17668        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17669        cx: &mut Context<Self>,
17670    ) -> bool {
17671        self.display_map
17672            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17673    }
17674
17675    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17676        self.display_map.read(cx).fold_placeholder.clone()
17677    }
17678
17679    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17680        self.buffer.update(cx, |buffer, cx| {
17681            buffer.set_all_diff_hunks_expanded(cx);
17682        });
17683    }
17684
17685    pub fn expand_all_diff_hunks(
17686        &mut self,
17687        _: &ExpandAllDiffHunks,
17688        _window: &mut Window,
17689        cx: &mut Context<Self>,
17690    ) {
17691        self.buffer.update(cx, |buffer, cx| {
17692            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17693        });
17694    }
17695
17696    pub fn toggle_selected_diff_hunks(
17697        &mut self,
17698        _: &ToggleSelectedDiffHunks,
17699        _window: &mut Window,
17700        cx: &mut Context<Self>,
17701    ) {
17702        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17703        self.toggle_diff_hunks_in_ranges(ranges, cx);
17704    }
17705
17706    pub fn diff_hunks_in_ranges<'a>(
17707        &'a self,
17708        ranges: &'a [Range<Anchor>],
17709        buffer: &'a MultiBufferSnapshot,
17710    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17711        ranges.iter().flat_map(move |range| {
17712            let end_excerpt_id = range.end.excerpt_id;
17713            let range = range.to_point(buffer);
17714            let mut peek_end = range.end;
17715            if range.end.row < buffer.max_row().0 {
17716                peek_end = Point::new(range.end.row + 1, 0);
17717            }
17718            buffer
17719                .diff_hunks_in_range(range.start..peek_end)
17720                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17721        })
17722    }
17723
17724    pub fn has_stageable_diff_hunks_in_ranges(
17725        &self,
17726        ranges: &[Range<Anchor>],
17727        snapshot: &MultiBufferSnapshot,
17728    ) -> bool {
17729        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17730        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17731    }
17732
17733    pub fn toggle_staged_selected_diff_hunks(
17734        &mut self,
17735        _: &::git::ToggleStaged,
17736        _: &mut Window,
17737        cx: &mut Context<Self>,
17738    ) {
17739        let snapshot = self.buffer.read(cx).snapshot(cx);
17740        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17741        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17742        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17743    }
17744
17745    pub fn set_render_diff_hunk_controls(
17746        &mut self,
17747        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17748        cx: &mut Context<Self>,
17749    ) {
17750        self.render_diff_hunk_controls = render_diff_hunk_controls;
17751        cx.notify();
17752    }
17753
17754    pub fn stage_and_next(
17755        &mut self,
17756        _: &::git::StageAndNext,
17757        window: &mut Window,
17758        cx: &mut Context<Self>,
17759    ) {
17760        self.do_stage_or_unstage_and_next(true, window, cx);
17761    }
17762
17763    pub fn unstage_and_next(
17764        &mut self,
17765        _: &::git::UnstageAndNext,
17766        window: &mut Window,
17767        cx: &mut Context<Self>,
17768    ) {
17769        self.do_stage_or_unstage_and_next(false, window, cx);
17770    }
17771
17772    pub fn stage_or_unstage_diff_hunks(
17773        &mut self,
17774        stage: bool,
17775        ranges: Vec<Range<Anchor>>,
17776        cx: &mut Context<Self>,
17777    ) {
17778        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17779        cx.spawn(async move |this, cx| {
17780            task.await?;
17781            this.update(cx, |this, cx| {
17782                let snapshot = this.buffer.read(cx).snapshot(cx);
17783                let chunk_by = this
17784                    .diff_hunks_in_ranges(&ranges, &snapshot)
17785                    .chunk_by(|hunk| hunk.buffer_id);
17786                for (buffer_id, hunks) in &chunk_by {
17787                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17788                }
17789            })
17790        })
17791        .detach_and_log_err(cx);
17792    }
17793
17794    fn save_buffers_for_ranges_if_needed(
17795        &mut self,
17796        ranges: &[Range<Anchor>],
17797        cx: &mut Context<Editor>,
17798    ) -> Task<Result<()>> {
17799        let multibuffer = self.buffer.read(cx);
17800        let snapshot = multibuffer.read(cx);
17801        let buffer_ids: HashSet<_> = ranges
17802            .iter()
17803            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17804            .collect();
17805        drop(snapshot);
17806
17807        let mut buffers = HashSet::default();
17808        for buffer_id in buffer_ids {
17809            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17810                let buffer = buffer_entity.read(cx);
17811                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17812                {
17813                    buffers.insert(buffer_entity);
17814                }
17815            }
17816        }
17817
17818        if let Some(project) = &self.project {
17819            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17820        } else {
17821            Task::ready(Ok(()))
17822        }
17823    }
17824
17825    fn do_stage_or_unstage_and_next(
17826        &mut self,
17827        stage: bool,
17828        window: &mut Window,
17829        cx: &mut Context<Self>,
17830    ) {
17831        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17832
17833        if ranges.iter().any(|range| range.start != range.end) {
17834            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17835            return;
17836        }
17837
17838        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17839        let snapshot = self.snapshot(window, cx);
17840        let position = self.selections.newest::<Point>(cx).head();
17841        let mut row = snapshot
17842            .buffer_snapshot
17843            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17844            .find(|hunk| hunk.row_range.start.0 > position.row)
17845            .map(|hunk| hunk.row_range.start);
17846
17847        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17848        // Outside of the project diff editor, wrap around to the beginning.
17849        if !all_diff_hunks_expanded {
17850            row = row.or_else(|| {
17851                snapshot
17852                    .buffer_snapshot
17853                    .diff_hunks_in_range(Point::zero()..position)
17854                    .find(|hunk| hunk.row_range.end.0 < position.row)
17855                    .map(|hunk| hunk.row_range.start)
17856            });
17857        }
17858
17859        if let Some(row) = row {
17860            let destination = Point::new(row.0, 0);
17861            let autoscroll = Autoscroll::center();
17862
17863            self.unfold_ranges(&[destination..destination], false, false, cx);
17864            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17865                s.select_ranges([destination..destination]);
17866            });
17867        }
17868    }
17869
17870    fn do_stage_or_unstage(
17871        &self,
17872        stage: bool,
17873        buffer_id: BufferId,
17874        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17875        cx: &mut App,
17876    ) -> Option<()> {
17877        let project = self.project.as_ref()?;
17878        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17879        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17880        let buffer_snapshot = buffer.read(cx).snapshot();
17881        let file_exists = buffer_snapshot
17882            .file()
17883            .is_some_and(|file| file.disk_state().exists());
17884        diff.update(cx, |diff, cx| {
17885            diff.stage_or_unstage_hunks(
17886                stage,
17887                &hunks
17888                    .map(|hunk| buffer_diff::DiffHunk {
17889                        buffer_range: hunk.buffer_range,
17890                        diff_base_byte_range: hunk.diff_base_byte_range,
17891                        secondary_status: hunk.secondary_status,
17892                        range: Point::zero()..Point::zero(), // unused
17893                    })
17894                    .collect::<Vec<_>>(),
17895                &buffer_snapshot,
17896                file_exists,
17897                cx,
17898            )
17899        });
17900        None
17901    }
17902
17903    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17904        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17905        self.buffer
17906            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17907    }
17908
17909    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17910        self.buffer.update(cx, |buffer, cx| {
17911            let ranges = vec![Anchor::min()..Anchor::max()];
17912            if !buffer.all_diff_hunks_expanded()
17913                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17914            {
17915                buffer.collapse_diff_hunks(ranges, cx);
17916                true
17917            } else {
17918                false
17919            }
17920        })
17921    }
17922
17923    fn toggle_diff_hunks_in_ranges(
17924        &mut self,
17925        ranges: Vec<Range<Anchor>>,
17926        cx: &mut Context<Editor>,
17927    ) {
17928        self.buffer.update(cx, |buffer, cx| {
17929            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17930            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17931        })
17932    }
17933
17934    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17935        self.buffer.update(cx, |buffer, cx| {
17936            let snapshot = buffer.snapshot(cx);
17937            let excerpt_id = range.end.excerpt_id;
17938            let point_range = range.to_point(&snapshot);
17939            let expand = !buffer.single_hunk_is_expanded(range, cx);
17940            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17941        })
17942    }
17943
17944    pub(crate) fn apply_all_diff_hunks(
17945        &mut self,
17946        _: &ApplyAllDiffHunks,
17947        window: &mut Window,
17948        cx: &mut Context<Self>,
17949    ) {
17950        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17951
17952        let buffers = self.buffer.read(cx).all_buffers();
17953        for branch_buffer in buffers {
17954            branch_buffer.update(cx, |branch_buffer, cx| {
17955                branch_buffer.merge_into_base(Vec::new(), cx);
17956            });
17957        }
17958
17959        if let Some(project) = self.project.clone() {
17960            self.save(
17961                SaveOptions {
17962                    format: true,
17963                    autosave: false,
17964                },
17965                project,
17966                window,
17967                cx,
17968            )
17969            .detach_and_log_err(cx);
17970        }
17971    }
17972
17973    pub(crate) fn apply_selected_diff_hunks(
17974        &mut self,
17975        _: &ApplyDiffHunk,
17976        window: &mut Window,
17977        cx: &mut Context<Self>,
17978    ) {
17979        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17980        let snapshot = self.snapshot(window, cx);
17981        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17982        let mut ranges_by_buffer = HashMap::default();
17983        self.transact(window, cx, |editor, _window, cx| {
17984            for hunk in hunks {
17985                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17986                    ranges_by_buffer
17987                        .entry(buffer.clone())
17988                        .or_insert_with(Vec::new)
17989                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17990                }
17991            }
17992
17993            for (buffer, ranges) in ranges_by_buffer {
17994                buffer.update(cx, |buffer, cx| {
17995                    buffer.merge_into_base(ranges, cx);
17996                });
17997            }
17998        });
17999
18000        if let Some(project) = self.project.clone() {
18001            self.save(
18002                SaveOptions {
18003                    format: true,
18004                    autosave: false,
18005                },
18006                project,
18007                window,
18008                cx,
18009            )
18010            .detach_and_log_err(cx);
18011        }
18012    }
18013
18014    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18015        if hovered != self.gutter_hovered {
18016            self.gutter_hovered = hovered;
18017            cx.notify();
18018        }
18019    }
18020
18021    pub fn insert_blocks(
18022        &mut self,
18023        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18024        autoscroll: Option<Autoscroll>,
18025        cx: &mut Context<Self>,
18026    ) -> Vec<CustomBlockId> {
18027        let blocks = self
18028            .display_map
18029            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18030        if let Some(autoscroll) = autoscroll {
18031            self.request_autoscroll(autoscroll, cx);
18032        }
18033        cx.notify();
18034        blocks
18035    }
18036
18037    pub fn resize_blocks(
18038        &mut self,
18039        heights: HashMap<CustomBlockId, u32>,
18040        autoscroll: Option<Autoscroll>,
18041        cx: &mut Context<Self>,
18042    ) {
18043        self.display_map
18044            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18045        if let Some(autoscroll) = autoscroll {
18046            self.request_autoscroll(autoscroll, cx);
18047        }
18048        cx.notify();
18049    }
18050
18051    pub fn replace_blocks(
18052        &mut self,
18053        renderers: HashMap<CustomBlockId, RenderBlock>,
18054        autoscroll: Option<Autoscroll>,
18055        cx: &mut Context<Self>,
18056    ) {
18057        self.display_map
18058            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18059        if let Some(autoscroll) = autoscroll {
18060            self.request_autoscroll(autoscroll, cx);
18061        }
18062        cx.notify();
18063    }
18064
18065    pub fn remove_blocks(
18066        &mut self,
18067        block_ids: HashSet<CustomBlockId>,
18068        autoscroll: Option<Autoscroll>,
18069        cx: &mut Context<Self>,
18070    ) {
18071        self.display_map.update(cx, |display_map, cx| {
18072            display_map.remove_blocks(block_ids, cx)
18073        });
18074        if let Some(autoscroll) = autoscroll {
18075            self.request_autoscroll(autoscroll, cx);
18076        }
18077        cx.notify();
18078    }
18079
18080    pub fn row_for_block(
18081        &self,
18082        block_id: CustomBlockId,
18083        cx: &mut Context<Self>,
18084    ) -> Option<DisplayRow> {
18085        self.display_map
18086            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18087    }
18088
18089    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18090        self.focused_block = Some(focused_block);
18091    }
18092
18093    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18094        self.focused_block.take()
18095    }
18096
18097    pub fn insert_creases(
18098        &mut self,
18099        creases: impl IntoIterator<Item = Crease<Anchor>>,
18100        cx: &mut Context<Self>,
18101    ) -> Vec<CreaseId> {
18102        self.display_map
18103            .update(cx, |map, cx| map.insert_creases(creases, cx))
18104    }
18105
18106    pub fn remove_creases(
18107        &mut self,
18108        ids: impl IntoIterator<Item = CreaseId>,
18109        cx: &mut Context<Self>,
18110    ) -> Vec<(CreaseId, Range<Anchor>)> {
18111        self.display_map
18112            .update(cx, |map, cx| map.remove_creases(ids, cx))
18113    }
18114
18115    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18116        self.display_map
18117            .update(cx, |map, cx| map.snapshot(cx))
18118            .longest_row()
18119    }
18120
18121    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18122        self.display_map
18123            .update(cx, |map, cx| map.snapshot(cx))
18124            .max_point()
18125    }
18126
18127    pub fn text(&self, cx: &App) -> String {
18128        self.buffer.read(cx).read(cx).text()
18129    }
18130
18131    pub fn is_empty(&self, cx: &App) -> bool {
18132        self.buffer.read(cx).read(cx).is_empty()
18133    }
18134
18135    pub fn text_option(&self, cx: &App) -> Option<String> {
18136        let text = self.text(cx);
18137        let text = text.trim();
18138
18139        if text.is_empty() {
18140            return None;
18141        }
18142
18143        Some(text.to_string())
18144    }
18145
18146    pub fn set_text(
18147        &mut self,
18148        text: impl Into<Arc<str>>,
18149        window: &mut Window,
18150        cx: &mut Context<Self>,
18151    ) {
18152        self.transact(window, cx, |this, _, cx| {
18153            this.buffer
18154                .read(cx)
18155                .as_singleton()
18156                .expect("you can only call set_text on editors for singleton buffers")
18157                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18158        });
18159    }
18160
18161    pub fn display_text(&self, cx: &mut App) -> String {
18162        self.display_map
18163            .update(cx, |map, cx| map.snapshot(cx))
18164            .text()
18165    }
18166
18167    fn create_minimap(
18168        &self,
18169        minimap_settings: MinimapSettings,
18170        window: &mut Window,
18171        cx: &mut Context<Self>,
18172    ) -> Option<Entity<Self>> {
18173        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18174            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18175    }
18176
18177    fn initialize_new_minimap(
18178        &self,
18179        minimap_settings: MinimapSettings,
18180        window: &mut Window,
18181        cx: &mut Context<Self>,
18182    ) -> Entity<Self> {
18183        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18184
18185        let mut minimap = Editor::new_internal(
18186            EditorMode::Minimap {
18187                parent: cx.weak_entity(),
18188            },
18189            self.buffer.clone(),
18190            None,
18191            Some(self.display_map.clone()),
18192            window,
18193            cx,
18194        );
18195        minimap.scroll_manager.clone_state(&self.scroll_manager);
18196        minimap.set_text_style_refinement(TextStyleRefinement {
18197            font_size: Some(MINIMAP_FONT_SIZE),
18198            font_weight: Some(MINIMAP_FONT_WEIGHT),
18199            ..Default::default()
18200        });
18201        minimap.update_minimap_configuration(minimap_settings, cx);
18202        cx.new(|_| minimap)
18203    }
18204
18205    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18206        let current_line_highlight = minimap_settings
18207            .current_line_highlight
18208            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18209        self.set_current_line_highlight(Some(current_line_highlight));
18210    }
18211
18212    pub fn minimap(&self) -> Option<&Entity<Self>> {
18213        self.minimap
18214            .as_ref()
18215            .filter(|_| self.minimap_visibility.visible())
18216    }
18217
18218    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18219        let mut wrap_guides = smallvec![];
18220
18221        if self.show_wrap_guides == Some(false) {
18222            return wrap_guides;
18223        }
18224
18225        let settings = self.buffer.read(cx).language_settings(cx);
18226        if settings.show_wrap_guides {
18227            match self.soft_wrap_mode(cx) {
18228                SoftWrap::Column(soft_wrap) => {
18229                    wrap_guides.push((soft_wrap as usize, true));
18230                }
18231                SoftWrap::Bounded(soft_wrap) => {
18232                    wrap_guides.push((soft_wrap as usize, true));
18233                }
18234                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18235            }
18236            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18237        }
18238
18239        wrap_guides
18240    }
18241
18242    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18243        let settings = self.buffer.read(cx).language_settings(cx);
18244        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18245        match mode {
18246            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18247                SoftWrap::None
18248            }
18249            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18250            language_settings::SoftWrap::PreferredLineLength => {
18251                SoftWrap::Column(settings.preferred_line_length)
18252            }
18253            language_settings::SoftWrap::Bounded => {
18254                SoftWrap::Bounded(settings.preferred_line_length)
18255            }
18256        }
18257    }
18258
18259    pub fn set_soft_wrap_mode(
18260        &mut self,
18261        mode: language_settings::SoftWrap,
18262
18263        cx: &mut Context<Self>,
18264    ) {
18265        self.soft_wrap_mode_override = Some(mode);
18266        cx.notify();
18267    }
18268
18269    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18270        self.hard_wrap = hard_wrap;
18271        cx.notify();
18272    }
18273
18274    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18275        self.text_style_refinement = Some(style);
18276    }
18277
18278    /// called by the Element so we know what style we were most recently rendered with.
18279    pub(crate) fn set_style(
18280        &mut self,
18281        style: EditorStyle,
18282        window: &mut Window,
18283        cx: &mut Context<Self>,
18284    ) {
18285        // We intentionally do not inform the display map about the minimap style
18286        // so that wrapping is not recalculated and stays consistent for the editor
18287        // and its linked minimap.
18288        if !self.mode.is_minimap() {
18289            let rem_size = window.rem_size();
18290            self.display_map.update(cx, |map, cx| {
18291                map.set_font(
18292                    style.text.font(),
18293                    style.text.font_size.to_pixels(rem_size),
18294                    cx,
18295                )
18296            });
18297        }
18298        self.style = Some(style);
18299    }
18300
18301    pub fn style(&self) -> Option<&EditorStyle> {
18302        self.style.as_ref()
18303    }
18304
18305    // Called by the element. This method is not designed to be called outside of the editor
18306    // element's layout code because it does not notify when rewrapping is computed synchronously.
18307    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18308        self.display_map
18309            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18310    }
18311
18312    pub fn set_soft_wrap(&mut self) {
18313        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18314    }
18315
18316    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18317        if self.soft_wrap_mode_override.is_some() {
18318            self.soft_wrap_mode_override.take();
18319        } else {
18320            let soft_wrap = match self.soft_wrap_mode(cx) {
18321                SoftWrap::GitDiff => return,
18322                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18323                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18324                    language_settings::SoftWrap::None
18325                }
18326            };
18327            self.soft_wrap_mode_override = Some(soft_wrap);
18328        }
18329        cx.notify();
18330    }
18331
18332    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18333        let Some(workspace) = self.workspace() else {
18334            return;
18335        };
18336        let fs = workspace.read(cx).app_state().fs.clone();
18337        let current_show = TabBarSettings::get_global(cx).show;
18338        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18339            setting.show = Some(!current_show);
18340        });
18341    }
18342
18343    pub fn toggle_indent_guides(
18344        &mut self,
18345        _: &ToggleIndentGuides,
18346        _: &mut Window,
18347        cx: &mut Context<Self>,
18348    ) {
18349        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18350            self.buffer
18351                .read(cx)
18352                .language_settings(cx)
18353                .indent_guides
18354                .enabled
18355        });
18356        self.show_indent_guides = Some(!currently_enabled);
18357        cx.notify();
18358    }
18359
18360    fn should_show_indent_guides(&self) -> Option<bool> {
18361        self.show_indent_guides
18362    }
18363
18364    pub fn toggle_line_numbers(
18365        &mut self,
18366        _: &ToggleLineNumbers,
18367        _: &mut Window,
18368        cx: &mut Context<Self>,
18369    ) {
18370        let mut editor_settings = EditorSettings::get_global(cx).clone();
18371        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18372        EditorSettings::override_global(editor_settings, cx);
18373    }
18374
18375    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18376        if let Some(show_line_numbers) = self.show_line_numbers {
18377            return show_line_numbers;
18378        }
18379        EditorSettings::get_global(cx).gutter.line_numbers
18380    }
18381
18382    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18383        self.use_relative_line_numbers
18384            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18385    }
18386
18387    pub fn toggle_relative_line_numbers(
18388        &mut self,
18389        _: &ToggleRelativeLineNumbers,
18390        _: &mut Window,
18391        cx: &mut Context<Self>,
18392    ) {
18393        let is_relative = self.should_use_relative_line_numbers(cx);
18394        self.set_relative_line_number(Some(!is_relative), cx)
18395    }
18396
18397    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18398        self.use_relative_line_numbers = is_relative;
18399        cx.notify();
18400    }
18401
18402    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18403        self.show_gutter = show_gutter;
18404        cx.notify();
18405    }
18406
18407    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18408        self.show_scrollbars = ScrollbarAxes {
18409            horizontal: show,
18410            vertical: show,
18411        };
18412        cx.notify();
18413    }
18414
18415    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18416        self.show_scrollbars.vertical = show;
18417        cx.notify();
18418    }
18419
18420    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18421        self.show_scrollbars.horizontal = show;
18422        cx.notify();
18423    }
18424
18425    pub fn set_minimap_visibility(
18426        &mut self,
18427        minimap_visibility: MinimapVisibility,
18428        window: &mut Window,
18429        cx: &mut Context<Self>,
18430    ) {
18431        if self.minimap_visibility != minimap_visibility {
18432            if minimap_visibility.visible() && self.minimap.is_none() {
18433                let minimap_settings = EditorSettings::get_global(cx).minimap;
18434                self.minimap =
18435                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18436            }
18437            self.minimap_visibility = minimap_visibility;
18438            cx.notify();
18439        }
18440    }
18441
18442    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18443        self.set_show_scrollbars(false, cx);
18444        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18445    }
18446
18447    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18448        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18449    }
18450
18451    /// Normally the text in full mode and auto height editors is padded on the
18452    /// left side by roughly half a character width for improved hit testing.
18453    ///
18454    /// Use this method to disable this for cases where this is not wanted (e.g.
18455    /// if you want to align the editor text with some other text above or below)
18456    /// or if you want to add this padding to single-line editors.
18457    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18458        self.offset_content = offset_content;
18459        cx.notify();
18460    }
18461
18462    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18463        self.show_line_numbers = Some(show_line_numbers);
18464        cx.notify();
18465    }
18466
18467    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18468        self.disable_expand_excerpt_buttons = true;
18469        cx.notify();
18470    }
18471
18472    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18473        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18474        cx.notify();
18475    }
18476
18477    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18478        self.show_code_actions = Some(show_code_actions);
18479        cx.notify();
18480    }
18481
18482    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18483        self.show_runnables = Some(show_runnables);
18484        cx.notify();
18485    }
18486
18487    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18488        self.show_breakpoints = Some(show_breakpoints);
18489        cx.notify();
18490    }
18491
18492    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18493        if self.display_map.read(cx).masked != masked {
18494            self.display_map.update(cx, |map, _| map.masked = masked);
18495        }
18496        cx.notify()
18497    }
18498
18499    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18500        self.show_wrap_guides = Some(show_wrap_guides);
18501        cx.notify();
18502    }
18503
18504    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18505        self.show_indent_guides = Some(show_indent_guides);
18506        cx.notify();
18507    }
18508
18509    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18510        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18511            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
18512                if let Some(dir) = file.abs_path(cx).parent() {
18513                    return Some(dir.to_owned());
18514                }
18515            }
18516
18517            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18518                return Some(project_path.path.to_path_buf());
18519            }
18520        }
18521
18522        None
18523    }
18524
18525    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18526        self.active_excerpt(cx)?
18527            .1
18528            .read(cx)
18529            .file()
18530            .and_then(|f| f.as_local())
18531    }
18532
18533    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18534        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18535            let buffer = buffer.read(cx);
18536            if let Some(project_path) = buffer.project_path(cx) {
18537                let project = self.project.as_ref()?.read(cx);
18538                project.absolute_path(&project_path, cx)
18539            } else {
18540                buffer
18541                    .file()
18542                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18543            }
18544        })
18545    }
18546
18547    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18548        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18549            let project_path = buffer.read(cx).project_path(cx)?;
18550            let project = self.project.as_ref()?.read(cx);
18551            let entry = project.entry_for_path(&project_path, cx)?;
18552            let path = entry.path.to_path_buf();
18553            Some(path)
18554        })
18555    }
18556
18557    pub fn reveal_in_finder(
18558        &mut self,
18559        _: &RevealInFileManager,
18560        _window: &mut Window,
18561        cx: &mut Context<Self>,
18562    ) {
18563        if let Some(target) = self.target_file(cx) {
18564            cx.reveal_path(&target.abs_path(cx));
18565        }
18566    }
18567
18568    pub fn copy_path(
18569        &mut self,
18570        _: &zed_actions::workspace::CopyPath,
18571        _window: &mut Window,
18572        cx: &mut Context<Self>,
18573    ) {
18574        if let Some(path) = self.target_file_abs_path(cx) {
18575            if let Some(path) = path.to_str() {
18576                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18577            }
18578        }
18579    }
18580
18581    pub fn copy_relative_path(
18582        &mut self,
18583        _: &zed_actions::workspace::CopyRelativePath,
18584        _window: &mut Window,
18585        cx: &mut Context<Self>,
18586    ) {
18587        if let Some(path) = self.target_file_path(cx) {
18588            if let Some(path) = path.to_str() {
18589                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18590            }
18591        }
18592    }
18593
18594    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18595        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18596            buffer.read(cx).project_path(cx)
18597        } else {
18598            None
18599        }
18600    }
18601
18602    // Returns true if the editor handled a go-to-line request
18603    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18604        maybe!({
18605            let breakpoint_store = self.breakpoint_store.as_ref()?;
18606
18607            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18608            else {
18609                self.clear_row_highlights::<ActiveDebugLine>();
18610                return None;
18611            };
18612
18613            let position = active_stack_frame.position;
18614            let buffer_id = position.buffer_id?;
18615            let snapshot = self
18616                .project
18617                .as_ref()?
18618                .read(cx)
18619                .buffer_for_id(buffer_id, cx)?
18620                .read(cx)
18621                .snapshot();
18622
18623            let mut handled = false;
18624            for (id, ExcerptRange { context, .. }) in
18625                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18626            {
18627                if context.start.cmp(&position, &snapshot).is_ge()
18628                    || context.end.cmp(&position, &snapshot).is_lt()
18629                {
18630                    continue;
18631                }
18632                let snapshot = self.buffer.read(cx).snapshot(cx);
18633                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18634
18635                handled = true;
18636                self.clear_row_highlights::<ActiveDebugLine>();
18637
18638                self.go_to_line::<ActiveDebugLine>(
18639                    multibuffer_anchor,
18640                    Some(cx.theme().colors().editor_debugger_active_line_background),
18641                    window,
18642                    cx,
18643                );
18644
18645                cx.notify();
18646            }
18647
18648            handled.then_some(())
18649        })
18650        .is_some()
18651    }
18652
18653    pub fn copy_file_name_without_extension(
18654        &mut self,
18655        _: &CopyFileNameWithoutExtension,
18656        _: &mut Window,
18657        cx: &mut Context<Self>,
18658    ) {
18659        if let Some(file) = self.target_file(cx) {
18660            if let Some(file_stem) = file.path().file_stem() {
18661                if let Some(name) = file_stem.to_str() {
18662                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18663                }
18664            }
18665        }
18666    }
18667
18668    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18669        if let Some(file) = self.target_file(cx) {
18670            if let Some(file_name) = file.path().file_name() {
18671                if let Some(name) = file_name.to_str() {
18672                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18673                }
18674            }
18675        }
18676    }
18677
18678    pub fn toggle_git_blame(
18679        &mut self,
18680        _: &::git::Blame,
18681        window: &mut Window,
18682        cx: &mut Context<Self>,
18683    ) {
18684        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18685
18686        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18687            self.start_git_blame(true, window, cx);
18688        }
18689
18690        cx.notify();
18691    }
18692
18693    pub fn toggle_git_blame_inline(
18694        &mut self,
18695        _: &ToggleGitBlameInline,
18696        window: &mut Window,
18697        cx: &mut Context<Self>,
18698    ) {
18699        self.toggle_git_blame_inline_internal(true, window, cx);
18700        cx.notify();
18701    }
18702
18703    pub fn open_git_blame_commit(
18704        &mut self,
18705        _: &OpenGitBlameCommit,
18706        window: &mut Window,
18707        cx: &mut Context<Self>,
18708    ) {
18709        self.open_git_blame_commit_internal(window, cx);
18710    }
18711
18712    fn open_git_blame_commit_internal(
18713        &mut self,
18714        window: &mut Window,
18715        cx: &mut Context<Self>,
18716    ) -> Option<()> {
18717        let blame = self.blame.as_ref()?;
18718        let snapshot = self.snapshot(window, cx);
18719        let cursor = self.selections.newest::<Point>(cx).head();
18720        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18721        let blame_entry = blame
18722            .update(cx, |blame, cx| {
18723                blame
18724                    .blame_for_rows(
18725                        &[RowInfo {
18726                            buffer_id: Some(buffer.remote_id()),
18727                            buffer_row: Some(point.row),
18728                            ..Default::default()
18729                        }],
18730                        cx,
18731                    )
18732                    .next()
18733            })
18734            .flatten()?;
18735        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18736        let repo = blame.read(cx).repository(cx)?;
18737        let workspace = self.workspace()?.downgrade();
18738        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18739        None
18740    }
18741
18742    pub fn git_blame_inline_enabled(&self) -> bool {
18743        self.git_blame_inline_enabled
18744    }
18745
18746    pub fn toggle_selection_menu(
18747        &mut self,
18748        _: &ToggleSelectionMenu,
18749        _: &mut Window,
18750        cx: &mut Context<Self>,
18751    ) {
18752        self.show_selection_menu = self
18753            .show_selection_menu
18754            .map(|show_selections_menu| !show_selections_menu)
18755            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18756
18757        cx.notify();
18758    }
18759
18760    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18761        self.show_selection_menu
18762            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18763    }
18764
18765    fn start_git_blame(
18766        &mut self,
18767        user_triggered: bool,
18768        window: &mut Window,
18769        cx: &mut Context<Self>,
18770    ) {
18771        if let Some(project) = self.project.as_ref() {
18772            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18773                return;
18774            };
18775
18776            if buffer.read(cx).file().is_none() {
18777                return;
18778            }
18779
18780            let focused = self.focus_handle(cx).contains_focused(window, cx);
18781
18782            let project = project.clone();
18783            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18784            self.blame_subscription =
18785                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18786            self.blame = Some(blame);
18787        }
18788    }
18789
18790    fn toggle_git_blame_inline_internal(
18791        &mut self,
18792        user_triggered: bool,
18793        window: &mut Window,
18794        cx: &mut Context<Self>,
18795    ) {
18796        if self.git_blame_inline_enabled {
18797            self.git_blame_inline_enabled = false;
18798            self.show_git_blame_inline = false;
18799            self.show_git_blame_inline_delay_task.take();
18800        } else {
18801            self.git_blame_inline_enabled = true;
18802            self.start_git_blame_inline(user_triggered, window, cx);
18803        }
18804
18805        cx.notify();
18806    }
18807
18808    fn start_git_blame_inline(
18809        &mut self,
18810        user_triggered: bool,
18811        window: &mut Window,
18812        cx: &mut Context<Self>,
18813    ) {
18814        self.start_git_blame(user_triggered, window, cx);
18815
18816        if ProjectSettings::get_global(cx)
18817            .git
18818            .inline_blame_delay()
18819            .is_some()
18820        {
18821            self.start_inline_blame_timer(window, cx);
18822        } else {
18823            self.show_git_blame_inline = true
18824        }
18825    }
18826
18827    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18828        self.blame.as_ref()
18829    }
18830
18831    pub fn show_git_blame_gutter(&self) -> bool {
18832        self.show_git_blame_gutter
18833    }
18834
18835    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18836        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18837    }
18838
18839    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18840        self.show_git_blame_inline
18841            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18842            && !self.newest_selection_head_on_empty_line(cx)
18843            && self.has_blame_entries(cx)
18844    }
18845
18846    fn has_blame_entries(&self, cx: &App) -> bool {
18847        self.blame()
18848            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18849    }
18850
18851    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18852        let cursor_anchor = self.selections.newest_anchor().head();
18853
18854        let snapshot = self.buffer.read(cx).snapshot(cx);
18855        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18856
18857        snapshot.line_len(buffer_row) == 0
18858    }
18859
18860    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18861        let buffer_and_selection = maybe!({
18862            let selection = self.selections.newest::<Point>(cx);
18863            let selection_range = selection.range();
18864
18865            let multi_buffer = self.buffer().read(cx);
18866            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18867            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18868
18869            let (buffer, range, _) = if selection.reversed {
18870                buffer_ranges.first()
18871            } else {
18872                buffer_ranges.last()
18873            }?;
18874
18875            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18876                ..text::ToPoint::to_point(&range.end, &buffer).row;
18877            Some((
18878                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18879                selection,
18880            ))
18881        });
18882
18883        let Some((buffer, selection)) = buffer_and_selection else {
18884            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18885        };
18886
18887        let Some(project) = self.project.as_ref() else {
18888            return Task::ready(Err(anyhow!("editor does not have project")));
18889        };
18890
18891        project.update(cx, |project, cx| {
18892            project.get_permalink_to_line(&buffer, selection, cx)
18893        })
18894    }
18895
18896    pub fn copy_permalink_to_line(
18897        &mut self,
18898        _: &CopyPermalinkToLine,
18899        window: &mut Window,
18900        cx: &mut Context<Self>,
18901    ) {
18902        let permalink_task = self.get_permalink_to_line(cx);
18903        let workspace = self.workspace();
18904
18905        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18906            Ok(permalink) => {
18907                cx.update(|_, cx| {
18908                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18909                })
18910                .ok();
18911            }
18912            Err(err) => {
18913                let message = format!("Failed to copy permalink: {err}");
18914
18915                anyhow::Result::<()>::Err(err).log_err();
18916
18917                if let Some(workspace) = workspace {
18918                    workspace
18919                        .update_in(cx, |workspace, _, cx| {
18920                            struct CopyPermalinkToLine;
18921
18922                            workspace.show_toast(
18923                                Toast::new(
18924                                    NotificationId::unique::<CopyPermalinkToLine>(),
18925                                    message,
18926                                ),
18927                                cx,
18928                            )
18929                        })
18930                        .ok();
18931                }
18932            }
18933        })
18934        .detach();
18935    }
18936
18937    pub fn copy_file_location(
18938        &mut self,
18939        _: &CopyFileLocation,
18940        _: &mut Window,
18941        cx: &mut Context<Self>,
18942    ) {
18943        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18944        if let Some(file) = self.target_file(cx) {
18945            if let Some(path) = file.path().to_str() {
18946                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18947            }
18948        }
18949    }
18950
18951    pub fn open_permalink_to_line(
18952        &mut self,
18953        _: &OpenPermalinkToLine,
18954        window: &mut Window,
18955        cx: &mut Context<Self>,
18956    ) {
18957        let permalink_task = self.get_permalink_to_line(cx);
18958        let workspace = self.workspace();
18959
18960        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18961            Ok(permalink) => {
18962                cx.update(|_, cx| {
18963                    cx.open_url(permalink.as_ref());
18964                })
18965                .ok();
18966            }
18967            Err(err) => {
18968                let message = format!("Failed to open permalink: {err}");
18969
18970                anyhow::Result::<()>::Err(err).log_err();
18971
18972                if let Some(workspace) = workspace {
18973                    workspace
18974                        .update(cx, |workspace, cx| {
18975                            struct OpenPermalinkToLine;
18976
18977                            workspace.show_toast(
18978                                Toast::new(
18979                                    NotificationId::unique::<OpenPermalinkToLine>(),
18980                                    message,
18981                                ),
18982                                cx,
18983                            )
18984                        })
18985                        .ok();
18986                }
18987            }
18988        })
18989        .detach();
18990    }
18991
18992    pub fn insert_uuid_v4(
18993        &mut self,
18994        _: &InsertUuidV4,
18995        window: &mut Window,
18996        cx: &mut Context<Self>,
18997    ) {
18998        self.insert_uuid(UuidVersion::V4, window, cx);
18999    }
19000
19001    pub fn insert_uuid_v7(
19002        &mut self,
19003        _: &InsertUuidV7,
19004        window: &mut Window,
19005        cx: &mut Context<Self>,
19006    ) {
19007        self.insert_uuid(UuidVersion::V7, window, cx);
19008    }
19009
19010    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19011        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19012        self.transact(window, cx, |this, window, cx| {
19013            let edits = this
19014                .selections
19015                .all::<Point>(cx)
19016                .into_iter()
19017                .map(|selection| {
19018                    let uuid = match version {
19019                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19020                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19021                    };
19022
19023                    (selection.range(), uuid.to_string())
19024                });
19025            this.edit(edits, cx);
19026            this.refresh_inline_completion(true, false, window, cx);
19027        });
19028    }
19029
19030    pub fn open_selections_in_multibuffer(
19031        &mut self,
19032        _: &OpenSelectionsInMultibuffer,
19033        window: &mut Window,
19034        cx: &mut Context<Self>,
19035    ) {
19036        let multibuffer = self.buffer.read(cx);
19037
19038        let Some(buffer) = multibuffer.as_singleton() else {
19039            return;
19040        };
19041
19042        let Some(workspace) = self.workspace() else {
19043            return;
19044        };
19045
19046        let title = multibuffer.title(cx).to_string();
19047
19048        let locations = self
19049            .selections
19050            .all_anchors(cx)
19051            .into_iter()
19052            .map(|selection| Location {
19053                buffer: buffer.clone(),
19054                range: selection.start.text_anchor..selection.end.text_anchor,
19055            })
19056            .collect::<Vec<_>>();
19057
19058        cx.spawn_in(window, async move |_, cx| {
19059            workspace.update_in(cx, |workspace, window, cx| {
19060                Self::open_locations_in_multibuffer(
19061                    workspace,
19062                    locations,
19063                    format!("Selections for '{title}'"),
19064                    false,
19065                    MultibufferSelectionMode::All,
19066                    window,
19067                    cx,
19068                );
19069            })
19070        })
19071        .detach();
19072    }
19073
19074    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19075    /// last highlight added will be used.
19076    ///
19077    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19078    pub fn highlight_rows<T: 'static>(
19079        &mut self,
19080        range: Range<Anchor>,
19081        color: Hsla,
19082        options: RowHighlightOptions,
19083        cx: &mut Context<Self>,
19084    ) {
19085        let snapshot = self.buffer().read(cx).snapshot(cx);
19086        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19087        let ix = row_highlights.binary_search_by(|highlight| {
19088            Ordering::Equal
19089                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19090                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19091        });
19092
19093        if let Err(mut ix) = ix {
19094            let index = post_inc(&mut self.highlight_order);
19095
19096            // If this range intersects with the preceding highlight, then merge it with
19097            // the preceding highlight. Otherwise insert a new highlight.
19098            let mut merged = false;
19099            if ix > 0 {
19100                let prev_highlight = &mut row_highlights[ix - 1];
19101                if prev_highlight
19102                    .range
19103                    .end
19104                    .cmp(&range.start, &snapshot)
19105                    .is_ge()
19106                {
19107                    ix -= 1;
19108                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19109                        prev_highlight.range.end = range.end;
19110                    }
19111                    merged = true;
19112                    prev_highlight.index = index;
19113                    prev_highlight.color = color;
19114                    prev_highlight.options = options;
19115                }
19116            }
19117
19118            if !merged {
19119                row_highlights.insert(
19120                    ix,
19121                    RowHighlight {
19122                        range: range.clone(),
19123                        index,
19124                        color,
19125                        options,
19126                        type_id: TypeId::of::<T>(),
19127                    },
19128                );
19129            }
19130
19131            // If any of the following highlights intersect with this one, merge them.
19132            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19133                let highlight = &row_highlights[ix];
19134                if next_highlight
19135                    .range
19136                    .start
19137                    .cmp(&highlight.range.end, &snapshot)
19138                    .is_le()
19139                {
19140                    if next_highlight
19141                        .range
19142                        .end
19143                        .cmp(&highlight.range.end, &snapshot)
19144                        .is_gt()
19145                    {
19146                        row_highlights[ix].range.end = next_highlight.range.end;
19147                    }
19148                    row_highlights.remove(ix + 1);
19149                } else {
19150                    break;
19151                }
19152            }
19153        }
19154    }
19155
19156    /// Remove any highlighted row ranges of the given type that intersect the
19157    /// given ranges.
19158    pub fn remove_highlighted_rows<T: 'static>(
19159        &mut self,
19160        ranges_to_remove: Vec<Range<Anchor>>,
19161        cx: &mut Context<Self>,
19162    ) {
19163        let snapshot = self.buffer().read(cx).snapshot(cx);
19164        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19165        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19166        row_highlights.retain(|highlight| {
19167            while let Some(range_to_remove) = ranges_to_remove.peek() {
19168                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19169                    Ordering::Less | Ordering::Equal => {
19170                        ranges_to_remove.next();
19171                    }
19172                    Ordering::Greater => {
19173                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19174                            Ordering::Less | Ordering::Equal => {
19175                                return false;
19176                            }
19177                            Ordering::Greater => break,
19178                        }
19179                    }
19180                }
19181            }
19182
19183            true
19184        })
19185    }
19186
19187    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19188    pub fn clear_row_highlights<T: 'static>(&mut self) {
19189        self.highlighted_rows.remove(&TypeId::of::<T>());
19190    }
19191
19192    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19193    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19194        self.highlighted_rows
19195            .get(&TypeId::of::<T>())
19196            .map_or(&[] as &[_], |vec| vec.as_slice())
19197            .iter()
19198            .map(|highlight| (highlight.range.clone(), highlight.color))
19199    }
19200
19201    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19202    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19203    /// Allows to ignore certain kinds of highlights.
19204    pub fn highlighted_display_rows(
19205        &self,
19206        window: &mut Window,
19207        cx: &mut App,
19208    ) -> BTreeMap<DisplayRow, LineHighlight> {
19209        let snapshot = self.snapshot(window, cx);
19210        let mut used_highlight_orders = HashMap::default();
19211        self.highlighted_rows
19212            .iter()
19213            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19214            .fold(
19215                BTreeMap::<DisplayRow, LineHighlight>::new(),
19216                |mut unique_rows, highlight| {
19217                    let start = highlight.range.start.to_display_point(&snapshot);
19218                    let end = highlight.range.end.to_display_point(&snapshot);
19219                    let start_row = start.row().0;
19220                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19221                        && end.column() == 0
19222                    {
19223                        end.row().0.saturating_sub(1)
19224                    } else {
19225                        end.row().0
19226                    };
19227                    for row in start_row..=end_row {
19228                        let used_index =
19229                            used_highlight_orders.entry(row).or_insert(highlight.index);
19230                        if highlight.index >= *used_index {
19231                            *used_index = highlight.index;
19232                            unique_rows.insert(
19233                                DisplayRow(row),
19234                                LineHighlight {
19235                                    include_gutter: highlight.options.include_gutter,
19236                                    border: None,
19237                                    background: highlight.color.into(),
19238                                    type_id: Some(highlight.type_id),
19239                                },
19240                            );
19241                        }
19242                    }
19243                    unique_rows
19244                },
19245            )
19246    }
19247
19248    pub fn highlighted_display_row_for_autoscroll(
19249        &self,
19250        snapshot: &DisplaySnapshot,
19251    ) -> Option<DisplayRow> {
19252        self.highlighted_rows
19253            .values()
19254            .flat_map(|highlighted_rows| highlighted_rows.iter())
19255            .filter_map(|highlight| {
19256                if highlight.options.autoscroll {
19257                    Some(highlight.range.start.to_display_point(snapshot).row())
19258                } else {
19259                    None
19260                }
19261            })
19262            .min()
19263    }
19264
19265    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19266        self.highlight_background::<SearchWithinRange>(
19267            ranges,
19268            |colors| colors.colors().editor_document_highlight_read_background,
19269            cx,
19270        )
19271    }
19272
19273    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19274        self.breadcrumb_header = Some(new_header);
19275    }
19276
19277    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19278        self.clear_background_highlights::<SearchWithinRange>(cx);
19279    }
19280
19281    pub fn highlight_background<T: 'static>(
19282        &mut self,
19283        ranges: &[Range<Anchor>],
19284        color_fetcher: fn(&Theme) -> Hsla,
19285        cx: &mut Context<Self>,
19286    ) {
19287        self.background_highlights.insert(
19288            HighlightKey::Type(TypeId::of::<T>()),
19289            (color_fetcher, Arc::from(ranges)),
19290        );
19291        self.scrollbar_marker_state.dirty = true;
19292        cx.notify();
19293    }
19294
19295    pub fn highlight_background_key<T: 'static>(
19296        &mut self,
19297        key: usize,
19298        ranges: &[Range<Anchor>],
19299        color_fetcher: fn(&Theme) -> Hsla,
19300        cx: &mut Context<Self>,
19301    ) {
19302        self.background_highlights.insert(
19303            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19304            (color_fetcher, Arc::from(ranges)),
19305        );
19306        self.scrollbar_marker_state.dirty = true;
19307        cx.notify();
19308    }
19309
19310    pub fn clear_background_highlights<T: 'static>(
19311        &mut self,
19312        cx: &mut Context<Self>,
19313    ) -> Option<BackgroundHighlight> {
19314        let text_highlights = self
19315            .background_highlights
19316            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19317        if !text_highlights.1.is_empty() {
19318            self.scrollbar_marker_state.dirty = true;
19319            cx.notify();
19320        }
19321        Some(text_highlights)
19322    }
19323
19324    pub fn highlight_gutter<T: 'static>(
19325        &mut self,
19326        ranges: impl Into<Vec<Range<Anchor>>>,
19327        color_fetcher: fn(&App) -> Hsla,
19328        cx: &mut Context<Self>,
19329    ) {
19330        self.gutter_highlights
19331            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19332        cx.notify();
19333    }
19334
19335    pub fn clear_gutter_highlights<T: 'static>(
19336        &mut self,
19337        cx: &mut Context<Self>,
19338    ) -> Option<GutterHighlight> {
19339        cx.notify();
19340        self.gutter_highlights.remove(&TypeId::of::<T>())
19341    }
19342
19343    pub fn insert_gutter_highlight<T: 'static>(
19344        &mut self,
19345        range: Range<Anchor>,
19346        color_fetcher: fn(&App) -> Hsla,
19347        cx: &mut Context<Self>,
19348    ) {
19349        let snapshot = self.buffer().read(cx).snapshot(cx);
19350        let mut highlights = self
19351            .gutter_highlights
19352            .remove(&TypeId::of::<T>())
19353            .map(|(_, highlights)| highlights)
19354            .unwrap_or_default();
19355        let ix = highlights.binary_search_by(|highlight| {
19356            Ordering::Equal
19357                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19358                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19359        });
19360        if let Err(ix) = ix {
19361            highlights.insert(ix, range);
19362        }
19363        self.gutter_highlights
19364            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19365    }
19366
19367    pub fn remove_gutter_highlights<T: 'static>(
19368        &mut self,
19369        ranges_to_remove: Vec<Range<Anchor>>,
19370        cx: &mut Context<Self>,
19371    ) {
19372        let snapshot = self.buffer().read(cx).snapshot(cx);
19373        let Some((color_fetcher, mut gutter_highlights)) =
19374            self.gutter_highlights.remove(&TypeId::of::<T>())
19375        else {
19376            return;
19377        };
19378        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19379        gutter_highlights.retain(|highlight| {
19380            while let Some(range_to_remove) = ranges_to_remove.peek() {
19381                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19382                    Ordering::Less | Ordering::Equal => {
19383                        ranges_to_remove.next();
19384                    }
19385                    Ordering::Greater => {
19386                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19387                            Ordering::Less | Ordering::Equal => {
19388                                return false;
19389                            }
19390                            Ordering::Greater => break,
19391                        }
19392                    }
19393                }
19394            }
19395
19396            true
19397        });
19398        self.gutter_highlights
19399            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19400    }
19401
19402    #[cfg(feature = "test-support")]
19403    pub fn all_text_highlights(
19404        &self,
19405        window: &mut Window,
19406        cx: &mut Context<Self>,
19407    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19408        let snapshot = self.snapshot(window, cx);
19409        self.display_map.update(cx, |display_map, _| {
19410            display_map
19411                .all_text_highlights()
19412                .map(|highlight| {
19413                    let (style, ranges) = highlight.as_ref();
19414                    (
19415                        *style,
19416                        ranges
19417                            .iter()
19418                            .map(|range| range.clone().to_display_points(&snapshot))
19419                            .collect(),
19420                    )
19421                })
19422                .collect()
19423        })
19424    }
19425
19426    #[cfg(feature = "test-support")]
19427    pub fn all_text_background_highlights(
19428        &self,
19429        window: &mut Window,
19430        cx: &mut Context<Self>,
19431    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19432        let snapshot = self.snapshot(window, cx);
19433        let buffer = &snapshot.buffer_snapshot;
19434        let start = buffer.anchor_before(0);
19435        let end = buffer.anchor_after(buffer.len());
19436        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19437    }
19438
19439    #[cfg(feature = "test-support")]
19440    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19441        let snapshot = self.buffer().read(cx).snapshot(cx);
19442
19443        let highlights = self
19444            .background_highlights
19445            .get(&HighlightKey::Type(TypeId::of::<
19446                items::BufferSearchHighlights,
19447            >()));
19448
19449        if let Some((_color, ranges)) = highlights {
19450            ranges
19451                .iter()
19452                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19453                .collect_vec()
19454        } else {
19455            vec![]
19456        }
19457    }
19458
19459    fn document_highlights_for_position<'a>(
19460        &'a self,
19461        position: Anchor,
19462        buffer: &'a MultiBufferSnapshot,
19463    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19464        let read_highlights = self
19465            .background_highlights
19466            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19467            .map(|h| &h.1);
19468        let write_highlights = self
19469            .background_highlights
19470            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19471            .map(|h| &h.1);
19472        let left_position = position.bias_left(buffer);
19473        let right_position = position.bias_right(buffer);
19474        read_highlights
19475            .into_iter()
19476            .chain(write_highlights)
19477            .flat_map(move |ranges| {
19478                let start_ix = match ranges.binary_search_by(|probe| {
19479                    let cmp = probe.end.cmp(&left_position, buffer);
19480                    if cmp.is_ge() {
19481                        Ordering::Greater
19482                    } else {
19483                        Ordering::Less
19484                    }
19485                }) {
19486                    Ok(i) | Err(i) => i,
19487                };
19488
19489                ranges[start_ix..]
19490                    .iter()
19491                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19492            })
19493    }
19494
19495    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19496        self.background_highlights
19497            .get(&HighlightKey::Type(TypeId::of::<T>()))
19498            .map_or(false, |(_, highlights)| !highlights.is_empty())
19499    }
19500
19501    pub fn background_highlights_in_range(
19502        &self,
19503        search_range: Range<Anchor>,
19504        display_snapshot: &DisplaySnapshot,
19505        theme: &Theme,
19506    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19507        let mut results = Vec::new();
19508        for (color_fetcher, ranges) in self.background_highlights.values() {
19509            let color = color_fetcher(theme);
19510            let start_ix = match ranges.binary_search_by(|probe| {
19511                let cmp = probe
19512                    .end
19513                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19514                if cmp.is_gt() {
19515                    Ordering::Greater
19516                } else {
19517                    Ordering::Less
19518                }
19519            }) {
19520                Ok(i) | Err(i) => i,
19521            };
19522            for range in &ranges[start_ix..] {
19523                if range
19524                    .start
19525                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19526                    .is_ge()
19527                {
19528                    break;
19529                }
19530
19531                let start = range.start.to_display_point(display_snapshot);
19532                let end = range.end.to_display_point(display_snapshot);
19533                results.push((start..end, color))
19534            }
19535        }
19536        results
19537    }
19538
19539    pub fn background_highlight_row_ranges<T: 'static>(
19540        &self,
19541        search_range: Range<Anchor>,
19542        display_snapshot: &DisplaySnapshot,
19543        count: usize,
19544    ) -> Vec<RangeInclusive<DisplayPoint>> {
19545        let mut results = Vec::new();
19546        let Some((_, ranges)) = self
19547            .background_highlights
19548            .get(&HighlightKey::Type(TypeId::of::<T>()))
19549        else {
19550            return vec![];
19551        };
19552
19553        let start_ix = match ranges.binary_search_by(|probe| {
19554            let cmp = probe
19555                .end
19556                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19557            if cmp.is_gt() {
19558                Ordering::Greater
19559            } else {
19560                Ordering::Less
19561            }
19562        }) {
19563            Ok(i) | Err(i) => i,
19564        };
19565        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19566            if let (Some(start_display), Some(end_display)) = (start, end) {
19567                results.push(
19568                    start_display.to_display_point(display_snapshot)
19569                        ..=end_display.to_display_point(display_snapshot),
19570                );
19571            }
19572        };
19573        let mut start_row: Option<Point> = None;
19574        let mut end_row: Option<Point> = None;
19575        if ranges.len() > count {
19576            return Vec::new();
19577        }
19578        for range in &ranges[start_ix..] {
19579            if range
19580                .start
19581                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19582                .is_ge()
19583            {
19584                break;
19585            }
19586            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19587            if let Some(current_row) = &end_row {
19588                if end.row == current_row.row {
19589                    continue;
19590                }
19591            }
19592            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19593            if start_row.is_none() {
19594                assert_eq!(end_row, None);
19595                start_row = Some(start);
19596                end_row = Some(end);
19597                continue;
19598            }
19599            if let Some(current_end) = end_row.as_mut() {
19600                if start.row > current_end.row + 1 {
19601                    push_region(start_row, end_row);
19602                    start_row = Some(start);
19603                    end_row = Some(end);
19604                } else {
19605                    // Merge two hunks.
19606                    *current_end = end;
19607                }
19608            } else {
19609                unreachable!();
19610            }
19611        }
19612        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19613        push_region(start_row, end_row);
19614        results
19615    }
19616
19617    pub fn gutter_highlights_in_range(
19618        &self,
19619        search_range: Range<Anchor>,
19620        display_snapshot: &DisplaySnapshot,
19621        cx: &App,
19622    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19623        let mut results = Vec::new();
19624        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19625            let color = color_fetcher(cx);
19626            let start_ix = match ranges.binary_search_by(|probe| {
19627                let cmp = probe
19628                    .end
19629                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19630                if cmp.is_gt() {
19631                    Ordering::Greater
19632                } else {
19633                    Ordering::Less
19634                }
19635            }) {
19636                Ok(i) | Err(i) => i,
19637            };
19638            for range in &ranges[start_ix..] {
19639                if range
19640                    .start
19641                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19642                    .is_ge()
19643                {
19644                    break;
19645                }
19646
19647                let start = range.start.to_display_point(display_snapshot);
19648                let end = range.end.to_display_point(display_snapshot);
19649                results.push((start..end, color))
19650            }
19651        }
19652        results
19653    }
19654
19655    /// Get the text ranges corresponding to the redaction query
19656    pub fn redacted_ranges(
19657        &self,
19658        search_range: Range<Anchor>,
19659        display_snapshot: &DisplaySnapshot,
19660        cx: &App,
19661    ) -> Vec<Range<DisplayPoint>> {
19662        display_snapshot
19663            .buffer_snapshot
19664            .redacted_ranges(search_range, |file| {
19665                if let Some(file) = file {
19666                    file.is_private()
19667                        && EditorSettings::get(
19668                            Some(SettingsLocation {
19669                                worktree_id: file.worktree_id(cx),
19670                                path: file.path().as_ref(),
19671                            }),
19672                            cx,
19673                        )
19674                        .redact_private_values
19675                } else {
19676                    false
19677                }
19678            })
19679            .map(|range| {
19680                range.start.to_display_point(display_snapshot)
19681                    ..range.end.to_display_point(display_snapshot)
19682            })
19683            .collect()
19684    }
19685
19686    pub fn highlight_text_key<T: 'static>(
19687        &mut self,
19688        key: usize,
19689        ranges: Vec<Range<Anchor>>,
19690        style: HighlightStyle,
19691        cx: &mut Context<Self>,
19692    ) {
19693        self.display_map.update(cx, |map, _| {
19694            map.highlight_text(
19695                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19696                ranges,
19697                style,
19698            );
19699        });
19700        cx.notify();
19701    }
19702
19703    pub fn highlight_text<T: 'static>(
19704        &mut self,
19705        ranges: Vec<Range<Anchor>>,
19706        style: HighlightStyle,
19707        cx: &mut Context<Self>,
19708    ) {
19709        self.display_map.update(cx, |map, _| {
19710            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19711        });
19712        cx.notify();
19713    }
19714
19715    pub(crate) fn highlight_inlays<T: 'static>(
19716        &mut self,
19717        highlights: Vec<InlayHighlight>,
19718        style: HighlightStyle,
19719        cx: &mut Context<Self>,
19720    ) {
19721        self.display_map.update(cx, |map, _| {
19722            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19723        });
19724        cx.notify();
19725    }
19726
19727    pub fn text_highlights<'a, T: 'static>(
19728        &'a self,
19729        cx: &'a App,
19730    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19731        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19732    }
19733
19734    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19735        let cleared = self
19736            .display_map
19737            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19738        if cleared {
19739            cx.notify();
19740        }
19741    }
19742
19743    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19744        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19745            && self.focus_handle.is_focused(window)
19746    }
19747
19748    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19749        self.show_cursor_when_unfocused = is_enabled;
19750        cx.notify();
19751    }
19752
19753    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19754        cx.notify();
19755    }
19756
19757    fn on_debug_session_event(
19758        &mut self,
19759        _session: Entity<Session>,
19760        event: &SessionEvent,
19761        cx: &mut Context<Self>,
19762    ) {
19763        match event {
19764            SessionEvent::InvalidateInlineValue => {
19765                self.refresh_inline_values(cx);
19766            }
19767            _ => {}
19768        }
19769    }
19770
19771    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19772        let Some(project) = self.project.clone() else {
19773            return;
19774        };
19775
19776        if !self.inline_value_cache.enabled {
19777            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19778            self.splice_inlays(&inlays, Vec::new(), cx);
19779            return;
19780        }
19781
19782        let current_execution_position = self
19783            .highlighted_rows
19784            .get(&TypeId::of::<ActiveDebugLine>())
19785            .and_then(|lines| lines.last().map(|line| line.range.end));
19786
19787        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19788            let inline_values = editor
19789                .update(cx, |editor, cx| {
19790                    let Some(current_execution_position) = current_execution_position else {
19791                        return Some(Task::ready(Ok(Vec::new())));
19792                    };
19793
19794                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19795                        let snapshot = buffer.snapshot(cx);
19796
19797                        let excerpt = snapshot.excerpt_containing(
19798                            current_execution_position..current_execution_position,
19799                        )?;
19800
19801                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19802                    })?;
19803
19804                    let range =
19805                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19806
19807                    project.inline_values(buffer, range, cx)
19808                })
19809                .ok()
19810                .flatten()?
19811                .await
19812                .context("refreshing debugger inlays")
19813                .log_err()?;
19814
19815            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19816
19817            for (buffer_id, inline_value) in inline_values
19818                .into_iter()
19819                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19820            {
19821                buffer_inline_values
19822                    .entry(buffer_id)
19823                    .or_default()
19824                    .push(inline_value);
19825            }
19826
19827            editor
19828                .update(cx, |editor, cx| {
19829                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19830                    let mut new_inlays = Vec::default();
19831
19832                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19833                        let buffer_id = buffer_snapshot.remote_id();
19834                        buffer_inline_values
19835                            .get(&buffer_id)
19836                            .into_iter()
19837                            .flatten()
19838                            .for_each(|hint| {
19839                                let inlay = Inlay::debugger(
19840                                    post_inc(&mut editor.next_inlay_id),
19841                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19842                                    hint.text(),
19843                                );
19844                                if !inlay.text.chars().contains(&'\n') {
19845                                    new_inlays.push(inlay);
19846                                }
19847                            });
19848                    }
19849
19850                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19851                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19852
19853                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19854                })
19855                .ok()?;
19856            Some(())
19857        });
19858    }
19859
19860    fn on_buffer_event(
19861        &mut self,
19862        multibuffer: &Entity<MultiBuffer>,
19863        event: &multi_buffer::Event,
19864        window: &mut Window,
19865        cx: &mut Context<Self>,
19866    ) {
19867        match event {
19868            multi_buffer::Event::Edited {
19869                singleton_buffer_edited,
19870                edited_buffer,
19871            } => {
19872                self.scrollbar_marker_state.dirty = true;
19873                self.active_indent_guides_state.dirty = true;
19874                self.refresh_active_diagnostics(cx);
19875                self.refresh_code_actions(window, cx);
19876                self.refresh_selected_text_highlights(true, window, cx);
19877                self.refresh_single_line_folds(window, cx);
19878                refresh_matching_bracket_highlights(self, window, cx);
19879                if self.has_active_inline_completion() {
19880                    self.update_visible_inline_completion(window, cx);
19881                }
19882                if let Some(project) = self.project.as_ref() {
19883                    if let Some(edited_buffer) = edited_buffer {
19884                        project.update(cx, |project, cx| {
19885                            self.registered_buffers
19886                                .entry(edited_buffer.read(cx).remote_id())
19887                                .or_insert_with(|| {
19888                                    project
19889                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19890                                });
19891                        });
19892                    }
19893                }
19894                cx.emit(EditorEvent::BufferEdited);
19895                cx.emit(SearchEvent::MatchesInvalidated);
19896
19897                if let Some(buffer) = edited_buffer {
19898                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
19899                }
19900
19901                if *singleton_buffer_edited {
19902                    if let Some(buffer) = edited_buffer {
19903                        if buffer.read(cx).file().is_none() {
19904                            cx.emit(EditorEvent::TitleChanged);
19905                        }
19906                    }
19907                    if let Some(project) = &self.project {
19908                        #[allow(clippy::mutable_key_type)]
19909                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19910                            multibuffer
19911                                .all_buffers()
19912                                .into_iter()
19913                                .filter_map(|buffer| {
19914                                    buffer.update(cx, |buffer, cx| {
19915                                        let language = buffer.language()?;
19916                                        let should_discard = project.update(cx, |project, cx| {
19917                                            project.is_local()
19918                                                && !project.has_language_servers_for(buffer, cx)
19919                                        });
19920                                        should_discard.not().then_some(language.clone())
19921                                    })
19922                                })
19923                                .collect::<HashSet<_>>()
19924                        });
19925                        if !languages_affected.is_empty() {
19926                            self.refresh_inlay_hints(
19927                                InlayHintRefreshReason::BufferEdited(languages_affected),
19928                                cx,
19929                            );
19930                        }
19931                    }
19932                }
19933
19934                let Some(project) = &self.project else { return };
19935                let (telemetry, is_via_ssh) = {
19936                    let project = project.read(cx);
19937                    let telemetry = project.client().telemetry().clone();
19938                    let is_via_ssh = project.is_via_ssh();
19939                    (telemetry, is_via_ssh)
19940                };
19941                refresh_linked_ranges(self, window, cx);
19942                telemetry.log_edit_event("editor", is_via_ssh);
19943            }
19944            multi_buffer::Event::ExcerptsAdded {
19945                buffer,
19946                predecessor,
19947                excerpts,
19948            } => {
19949                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19950                let buffer_id = buffer.read(cx).remote_id();
19951                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19952                    if let Some(project) = &self.project {
19953                        update_uncommitted_diff_for_buffer(
19954                            cx.entity(),
19955                            project,
19956                            [buffer.clone()],
19957                            self.buffer.clone(),
19958                            cx,
19959                        )
19960                        .detach();
19961                    }
19962                }
19963                self.update_lsp_data(false, Some(buffer_id), window, cx);
19964                cx.emit(EditorEvent::ExcerptsAdded {
19965                    buffer: buffer.clone(),
19966                    predecessor: *predecessor,
19967                    excerpts: excerpts.clone(),
19968                });
19969                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19970            }
19971            multi_buffer::Event::ExcerptsRemoved {
19972                ids,
19973                removed_buffer_ids,
19974            } => {
19975                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19976                let buffer = self.buffer.read(cx);
19977                self.registered_buffers
19978                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19979                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19980                cx.emit(EditorEvent::ExcerptsRemoved {
19981                    ids: ids.clone(),
19982                    removed_buffer_ids: removed_buffer_ids.clone(),
19983                });
19984            }
19985            multi_buffer::Event::ExcerptsEdited {
19986                excerpt_ids,
19987                buffer_ids,
19988            } => {
19989                self.display_map.update(cx, |map, cx| {
19990                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19991                });
19992                cx.emit(EditorEvent::ExcerptsEdited {
19993                    ids: excerpt_ids.clone(),
19994                });
19995            }
19996            multi_buffer::Event::ExcerptsExpanded { ids } => {
19997                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19998                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19999            }
20000            multi_buffer::Event::Reparsed(buffer_id) => {
20001                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20002                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20003
20004                cx.emit(EditorEvent::Reparsed(*buffer_id));
20005            }
20006            multi_buffer::Event::DiffHunksToggled => {
20007                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20008            }
20009            multi_buffer::Event::LanguageChanged(buffer_id) => {
20010                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20011                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20012                cx.emit(EditorEvent::Reparsed(*buffer_id));
20013                cx.notify();
20014            }
20015            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20016            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20017            multi_buffer::Event::FileHandleChanged
20018            | multi_buffer::Event::Reloaded
20019            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20020            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
20021            multi_buffer::Event::DiagnosticsUpdated => {
20022                self.update_diagnostics_state(window, cx);
20023            }
20024            _ => {}
20025        };
20026    }
20027
20028    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20029        if !self.diagnostics_enabled() {
20030            return;
20031        }
20032        self.refresh_active_diagnostics(cx);
20033        self.refresh_inline_diagnostics(true, window, cx);
20034        self.scrollbar_marker_state.dirty = true;
20035        cx.notify();
20036    }
20037
20038    pub fn start_temporary_diff_override(&mut self) {
20039        self.load_diff_task.take();
20040        self.temporary_diff_override = true;
20041    }
20042
20043    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20044        self.temporary_diff_override = false;
20045        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20046        self.buffer.update(cx, |buffer, cx| {
20047            buffer.set_all_diff_hunks_collapsed(cx);
20048        });
20049
20050        if let Some(project) = self.project.clone() {
20051            self.load_diff_task = Some(
20052                update_uncommitted_diff_for_buffer(
20053                    cx.entity(),
20054                    &project,
20055                    self.buffer.read(cx).all_buffers(),
20056                    self.buffer.clone(),
20057                    cx,
20058                )
20059                .shared(),
20060            );
20061        }
20062    }
20063
20064    fn on_display_map_changed(
20065        &mut self,
20066        _: Entity<DisplayMap>,
20067        _: &mut Window,
20068        cx: &mut Context<Self>,
20069    ) {
20070        cx.notify();
20071    }
20072
20073    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20074        if self.diagnostics_enabled() {
20075            let new_severity = EditorSettings::get_global(cx)
20076                .diagnostics_max_severity
20077                .unwrap_or(DiagnosticSeverity::Hint);
20078            self.set_max_diagnostics_severity(new_severity, cx);
20079        }
20080        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20081        self.update_edit_prediction_settings(cx);
20082        self.refresh_inline_completion(true, false, window, cx);
20083        self.refresh_inline_values(cx);
20084        self.refresh_inlay_hints(
20085            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20086                self.selections.newest_anchor().head(),
20087                &self.buffer.read(cx).snapshot(cx),
20088                cx,
20089            )),
20090            cx,
20091        );
20092
20093        let old_cursor_shape = self.cursor_shape;
20094
20095        {
20096            let editor_settings = EditorSettings::get_global(cx);
20097            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20098            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20099            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20100            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20101        }
20102
20103        if old_cursor_shape != self.cursor_shape {
20104            cx.emit(EditorEvent::CursorShapeChanged);
20105        }
20106
20107        let project_settings = ProjectSettings::get_global(cx);
20108        self.serialize_dirty_buffers =
20109            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20110
20111        if self.mode.is_full() {
20112            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20113            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20114            if self.show_inline_diagnostics != show_inline_diagnostics {
20115                self.show_inline_diagnostics = show_inline_diagnostics;
20116                self.refresh_inline_diagnostics(false, window, cx);
20117            }
20118
20119            if self.git_blame_inline_enabled != inline_blame_enabled {
20120                self.toggle_git_blame_inline_internal(false, window, cx);
20121            }
20122
20123            let minimap_settings = EditorSettings::get_global(cx).minimap;
20124            if self.minimap_visibility != MinimapVisibility::Disabled {
20125                if self.minimap_visibility.settings_visibility()
20126                    != minimap_settings.minimap_enabled()
20127                {
20128                    self.set_minimap_visibility(
20129                        MinimapVisibility::for_mode(self.mode(), cx),
20130                        window,
20131                        cx,
20132                    );
20133                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20134                    minimap_entity.update(cx, |minimap_editor, cx| {
20135                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20136                    })
20137                }
20138            }
20139        }
20140
20141        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20142            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20143        }) {
20144            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20145                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20146            }
20147            self.refresh_colors(false, None, window, cx);
20148        }
20149
20150        cx.notify();
20151    }
20152
20153    pub fn set_searchable(&mut self, searchable: bool) {
20154        self.searchable = searchable;
20155    }
20156
20157    pub fn searchable(&self) -> bool {
20158        self.searchable
20159    }
20160
20161    fn open_proposed_changes_editor(
20162        &mut self,
20163        _: &OpenProposedChangesEditor,
20164        window: &mut Window,
20165        cx: &mut Context<Self>,
20166    ) {
20167        let Some(workspace) = self.workspace() else {
20168            cx.propagate();
20169            return;
20170        };
20171
20172        let selections = self.selections.all::<usize>(cx);
20173        let multi_buffer = self.buffer.read(cx);
20174        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20175        let mut new_selections_by_buffer = HashMap::default();
20176        for selection in selections {
20177            for (buffer, range, _) in
20178                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20179            {
20180                let mut range = range.to_point(buffer);
20181                range.start.column = 0;
20182                range.end.column = buffer.line_len(range.end.row);
20183                new_selections_by_buffer
20184                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20185                    .or_insert(Vec::new())
20186                    .push(range)
20187            }
20188        }
20189
20190        let proposed_changes_buffers = new_selections_by_buffer
20191            .into_iter()
20192            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20193            .collect::<Vec<_>>();
20194        let proposed_changes_editor = cx.new(|cx| {
20195            ProposedChangesEditor::new(
20196                "Proposed changes",
20197                proposed_changes_buffers,
20198                self.project.clone(),
20199                window,
20200                cx,
20201            )
20202        });
20203
20204        window.defer(cx, move |window, cx| {
20205            workspace.update(cx, |workspace, cx| {
20206                workspace.active_pane().update(cx, |pane, cx| {
20207                    pane.add_item(
20208                        Box::new(proposed_changes_editor),
20209                        true,
20210                        true,
20211                        None,
20212                        window,
20213                        cx,
20214                    );
20215                });
20216            });
20217        });
20218    }
20219
20220    pub fn open_excerpts_in_split(
20221        &mut self,
20222        _: &OpenExcerptsSplit,
20223        window: &mut Window,
20224        cx: &mut Context<Self>,
20225    ) {
20226        self.open_excerpts_common(None, true, window, cx)
20227    }
20228
20229    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20230        self.open_excerpts_common(None, false, window, cx)
20231    }
20232
20233    fn open_excerpts_common(
20234        &mut self,
20235        jump_data: Option<JumpData>,
20236        split: bool,
20237        window: &mut Window,
20238        cx: &mut Context<Self>,
20239    ) {
20240        let Some(workspace) = self.workspace() else {
20241            cx.propagate();
20242            return;
20243        };
20244
20245        if self.buffer.read(cx).is_singleton() {
20246            cx.propagate();
20247            return;
20248        }
20249
20250        let mut new_selections_by_buffer = HashMap::default();
20251        match &jump_data {
20252            Some(JumpData::MultiBufferPoint {
20253                excerpt_id,
20254                position,
20255                anchor,
20256                line_offset_from_top,
20257            }) => {
20258                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20259                if let Some(buffer) = multi_buffer_snapshot
20260                    .buffer_id_for_excerpt(*excerpt_id)
20261                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20262                {
20263                    let buffer_snapshot = buffer.read(cx).snapshot();
20264                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20265                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20266                    } else {
20267                        buffer_snapshot.clip_point(*position, Bias::Left)
20268                    };
20269                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20270                    new_selections_by_buffer.insert(
20271                        buffer,
20272                        (
20273                            vec![jump_to_offset..jump_to_offset],
20274                            Some(*line_offset_from_top),
20275                        ),
20276                    );
20277                }
20278            }
20279            Some(JumpData::MultiBufferRow {
20280                row,
20281                line_offset_from_top,
20282            }) => {
20283                let point = MultiBufferPoint::new(row.0, 0);
20284                if let Some((buffer, buffer_point, _)) =
20285                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20286                {
20287                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20288                    new_selections_by_buffer
20289                        .entry(buffer)
20290                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20291                        .0
20292                        .push(buffer_offset..buffer_offset)
20293                }
20294            }
20295            None => {
20296                let selections = self.selections.all::<usize>(cx);
20297                let multi_buffer = self.buffer.read(cx);
20298                for selection in selections {
20299                    for (snapshot, range, _, anchor) in multi_buffer
20300                        .snapshot(cx)
20301                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20302                    {
20303                        if let Some(anchor) = anchor {
20304                            // selection is in a deleted hunk
20305                            let Some(buffer_id) = anchor.buffer_id else {
20306                                continue;
20307                            };
20308                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
20309                                continue;
20310                            };
20311                            let offset = text::ToOffset::to_offset(
20312                                &anchor.text_anchor,
20313                                &buffer_handle.read(cx).snapshot(),
20314                            );
20315                            let range = offset..offset;
20316                            new_selections_by_buffer
20317                                .entry(buffer_handle)
20318                                .or_insert((Vec::new(), None))
20319                                .0
20320                                .push(range)
20321                        } else {
20322                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20323                            else {
20324                                continue;
20325                            };
20326                            new_selections_by_buffer
20327                                .entry(buffer_handle)
20328                                .or_insert((Vec::new(), None))
20329                                .0
20330                                .push(range)
20331                        }
20332                    }
20333                }
20334            }
20335        }
20336
20337        new_selections_by_buffer
20338            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20339
20340        if new_selections_by_buffer.is_empty() {
20341            return;
20342        }
20343
20344        // We defer the pane interaction because we ourselves are a workspace item
20345        // and activating a new item causes the pane to call a method on us reentrantly,
20346        // which panics if we're on the stack.
20347        window.defer(cx, move |window, cx| {
20348            workspace.update(cx, |workspace, cx| {
20349                let pane = if split {
20350                    workspace.adjacent_pane(window, cx)
20351                } else {
20352                    workspace.active_pane().clone()
20353                };
20354
20355                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20356                    let editor = buffer
20357                        .read(cx)
20358                        .file()
20359                        .is_none()
20360                        .then(|| {
20361                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20362                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20363                            // Instead, we try to activate the existing editor in the pane first.
20364                            let (editor, pane_item_index) =
20365                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20366                                    let editor = item.downcast::<Editor>()?;
20367                                    let singleton_buffer =
20368                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20369                                    if singleton_buffer == buffer {
20370                                        Some((editor, i))
20371                                    } else {
20372                                        None
20373                                    }
20374                                })?;
20375                            pane.update(cx, |pane, cx| {
20376                                pane.activate_item(pane_item_index, true, true, window, cx)
20377                            });
20378                            Some(editor)
20379                        })
20380                        .flatten()
20381                        .unwrap_or_else(|| {
20382                            workspace.open_project_item::<Self>(
20383                                pane.clone(),
20384                                buffer,
20385                                true,
20386                                true,
20387                                window,
20388                                cx,
20389                            )
20390                        });
20391
20392                    editor.update(cx, |editor, cx| {
20393                        let autoscroll = match scroll_offset {
20394                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20395                            None => Autoscroll::newest(),
20396                        };
20397                        let nav_history = editor.nav_history.take();
20398                        editor.change_selections(
20399                            SelectionEffects::scroll(autoscroll),
20400                            window,
20401                            cx,
20402                            |s| {
20403                                s.select_ranges(ranges);
20404                            },
20405                        );
20406                        editor.nav_history = nav_history;
20407                    });
20408                }
20409            })
20410        });
20411    }
20412
20413    // For now, don't allow opening excerpts in buffers that aren't backed by
20414    // regular project files.
20415    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20416        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
20417    }
20418
20419    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20420        let snapshot = self.buffer.read(cx).read(cx);
20421        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20422        Some(
20423            ranges
20424                .iter()
20425                .map(move |range| {
20426                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20427                })
20428                .collect(),
20429        )
20430    }
20431
20432    fn selection_replacement_ranges(
20433        &self,
20434        range: Range<OffsetUtf16>,
20435        cx: &mut App,
20436    ) -> Vec<Range<OffsetUtf16>> {
20437        let selections = self.selections.all::<OffsetUtf16>(cx);
20438        let newest_selection = selections
20439            .iter()
20440            .max_by_key(|selection| selection.id)
20441            .unwrap();
20442        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20443        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20444        let snapshot = self.buffer.read(cx).read(cx);
20445        selections
20446            .into_iter()
20447            .map(|mut selection| {
20448                selection.start.0 =
20449                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20450                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20451                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20452                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20453            })
20454            .collect()
20455    }
20456
20457    fn report_editor_event(
20458        &self,
20459        event_type: &'static str,
20460        file_extension: Option<String>,
20461        cx: &App,
20462    ) {
20463        if cfg!(any(test, feature = "test-support")) {
20464            return;
20465        }
20466
20467        let Some(project) = &self.project else { return };
20468
20469        // If None, we are in a file without an extension
20470        let file = self
20471            .buffer
20472            .read(cx)
20473            .as_singleton()
20474            .and_then(|b| b.read(cx).file());
20475        let file_extension = file_extension.or(file
20476            .as_ref()
20477            .and_then(|file| Path::new(file.file_name(cx)).extension())
20478            .and_then(|e| e.to_str())
20479            .map(|a| a.to_string()));
20480
20481        let vim_mode = vim_enabled(cx);
20482
20483        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20484        let copilot_enabled = edit_predictions_provider
20485            == language::language_settings::EditPredictionProvider::Copilot;
20486        let copilot_enabled_for_language = self
20487            .buffer
20488            .read(cx)
20489            .language_settings(cx)
20490            .show_edit_predictions;
20491
20492        let project = project.read(cx);
20493        telemetry::event!(
20494            event_type,
20495            file_extension,
20496            vim_mode,
20497            copilot_enabled,
20498            copilot_enabled_for_language,
20499            edit_predictions_provider,
20500            is_via_ssh = project.is_via_ssh(),
20501        );
20502    }
20503
20504    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20505    /// with each line being an array of {text, highlight} objects.
20506    fn copy_highlight_json(
20507        &mut self,
20508        _: &CopyHighlightJson,
20509        window: &mut Window,
20510        cx: &mut Context<Self>,
20511    ) {
20512        #[derive(Serialize)]
20513        struct Chunk<'a> {
20514            text: String,
20515            highlight: Option<&'a str>,
20516        }
20517
20518        let snapshot = self.buffer.read(cx).snapshot(cx);
20519        let range = self
20520            .selected_text_range(false, window, cx)
20521            .and_then(|selection| {
20522                if selection.range.is_empty() {
20523                    None
20524                } else {
20525                    Some(selection.range)
20526                }
20527            })
20528            .unwrap_or_else(|| 0..snapshot.len());
20529
20530        let chunks = snapshot.chunks(range, true);
20531        let mut lines = Vec::new();
20532        let mut line: VecDeque<Chunk> = VecDeque::new();
20533
20534        let Some(style) = self.style.as_ref() else {
20535            return;
20536        };
20537
20538        for chunk in chunks {
20539            let highlight = chunk
20540                .syntax_highlight_id
20541                .and_then(|id| id.name(&style.syntax));
20542            let mut chunk_lines = chunk.text.split('\n').peekable();
20543            while let Some(text) = chunk_lines.next() {
20544                let mut merged_with_last_token = false;
20545                if let Some(last_token) = line.back_mut() {
20546                    if last_token.highlight == highlight {
20547                        last_token.text.push_str(text);
20548                        merged_with_last_token = true;
20549                    }
20550                }
20551
20552                if !merged_with_last_token {
20553                    line.push_back(Chunk {
20554                        text: text.into(),
20555                        highlight,
20556                    });
20557                }
20558
20559                if chunk_lines.peek().is_some() {
20560                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20561                        line.pop_front();
20562                    }
20563                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20564                        line.pop_back();
20565                    }
20566
20567                    lines.push(mem::take(&mut line));
20568                }
20569            }
20570        }
20571
20572        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20573            return;
20574        };
20575        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20576    }
20577
20578    pub fn open_context_menu(
20579        &mut self,
20580        _: &OpenContextMenu,
20581        window: &mut Window,
20582        cx: &mut Context<Self>,
20583    ) {
20584        self.request_autoscroll(Autoscroll::newest(), cx);
20585        let position = self.selections.newest_display(cx).start;
20586        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20587    }
20588
20589    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20590        &self.inlay_hint_cache
20591    }
20592
20593    pub fn replay_insert_event(
20594        &mut self,
20595        text: &str,
20596        relative_utf16_range: Option<Range<isize>>,
20597        window: &mut Window,
20598        cx: &mut Context<Self>,
20599    ) {
20600        if !self.input_enabled {
20601            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20602            return;
20603        }
20604        if let Some(relative_utf16_range) = relative_utf16_range {
20605            let selections = self.selections.all::<OffsetUtf16>(cx);
20606            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20607                let new_ranges = selections.into_iter().map(|range| {
20608                    let start = OffsetUtf16(
20609                        range
20610                            .head()
20611                            .0
20612                            .saturating_add_signed(relative_utf16_range.start),
20613                    );
20614                    let end = OffsetUtf16(
20615                        range
20616                            .head()
20617                            .0
20618                            .saturating_add_signed(relative_utf16_range.end),
20619                    );
20620                    start..end
20621                });
20622                s.select_ranges(new_ranges);
20623            });
20624        }
20625
20626        self.handle_input(text, window, cx);
20627    }
20628
20629    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20630        let Some(provider) = self.semantics_provider.as_ref() else {
20631            return false;
20632        };
20633
20634        let mut supports = false;
20635        self.buffer().update(cx, |this, cx| {
20636            this.for_each_buffer(|buffer| {
20637                supports |= provider.supports_inlay_hints(buffer, cx);
20638            });
20639        });
20640
20641        supports
20642    }
20643
20644    pub fn is_focused(&self, window: &Window) -> bool {
20645        self.focus_handle.is_focused(window)
20646    }
20647
20648    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20649        cx.emit(EditorEvent::Focused);
20650
20651        if let Some(descendant) = self
20652            .last_focused_descendant
20653            .take()
20654            .and_then(|descendant| descendant.upgrade())
20655        {
20656            window.focus(&descendant);
20657        } else {
20658            if let Some(blame) = self.blame.as_ref() {
20659                blame.update(cx, GitBlame::focus)
20660            }
20661
20662            self.blink_manager.update(cx, BlinkManager::enable);
20663            self.show_cursor_names(window, cx);
20664            self.buffer.update(cx, |buffer, cx| {
20665                buffer.finalize_last_transaction(cx);
20666                if self.leader_id.is_none() {
20667                    buffer.set_active_selections(
20668                        &self.selections.disjoint_anchors(),
20669                        self.selections.line_mode,
20670                        self.cursor_shape,
20671                        cx,
20672                    );
20673                }
20674            });
20675        }
20676    }
20677
20678    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20679        cx.emit(EditorEvent::FocusedIn)
20680    }
20681
20682    fn handle_focus_out(
20683        &mut self,
20684        event: FocusOutEvent,
20685        _window: &mut Window,
20686        cx: &mut Context<Self>,
20687    ) {
20688        if event.blurred != self.focus_handle {
20689            self.last_focused_descendant = Some(event.blurred);
20690        }
20691        self.selection_drag_state = SelectionDragState::None;
20692        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20693    }
20694
20695    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20696        self.blink_manager.update(cx, BlinkManager::disable);
20697        self.buffer
20698            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20699
20700        if let Some(blame) = self.blame.as_ref() {
20701            blame.update(cx, GitBlame::blur)
20702        }
20703        if !self.hover_state.focused(window, cx) {
20704            hide_hover(self, cx);
20705        }
20706        if !self
20707            .context_menu
20708            .borrow()
20709            .as_ref()
20710            .is_some_and(|context_menu| context_menu.focused(window, cx))
20711        {
20712            self.hide_context_menu(window, cx);
20713        }
20714        self.discard_inline_completion(false, cx);
20715        cx.emit(EditorEvent::Blurred);
20716        cx.notify();
20717    }
20718
20719    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20720        let mut pending: String = window
20721            .pending_input_keystrokes()
20722            .into_iter()
20723            .flatten()
20724            .filter_map(|keystroke| {
20725                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20726                    keystroke.key_char.clone()
20727                } else {
20728                    None
20729                }
20730            })
20731            .collect();
20732
20733        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20734            pending = "".to_string();
20735        }
20736
20737        let existing_pending = self
20738            .text_highlights::<PendingInput>(cx)
20739            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
20740        if existing_pending.is_none() && pending.is_empty() {
20741            return;
20742        }
20743        let transaction =
20744            self.transact(window, cx, |this, window, cx| {
20745                let selections = this.selections.all::<usize>(cx);
20746                let edits = selections
20747                    .iter()
20748                    .map(|selection| (selection.end..selection.end, pending.clone()));
20749                this.edit(edits, cx);
20750                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20751                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20752                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20753                    }));
20754                });
20755                if let Some(existing_ranges) = existing_pending {
20756                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20757                    this.edit(edits, cx);
20758                }
20759            });
20760
20761        let snapshot = self.snapshot(window, cx);
20762        let ranges = self
20763            .selections
20764            .all::<usize>(cx)
20765            .into_iter()
20766            .map(|selection| {
20767                snapshot.buffer_snapshot.anchor_after(selection.end)
20768                    ..snapshot
20769                        .buffer_snapshot
20770                        .anchor_before(selection.end + pending.len())
20771            })
20772            .collect();
20773
20774        if pending.is_empty() {
20775            self.clear_highlights::<PendingInput>(cx);
20776        } else {
20777            self.highlight_text::<PendingInput>(
20778                ranges,
20779                HighlightStyle {
20780                    underline: Some(UnderlineStyle {
20781                        thickness: px(1.),
20782                        color: None,
20783                        wavy: false,
20784                    }),
20785                    ..Default::default()
20786                },
20787                cx,
20788            );
20789        }
20790
20791        self.ime_transaction = self.ime_transaction.or(transaction);
20792        if let Some(transaction) = self.ime_transaction {
20793            self.buffer.update(cx, |buffer, cx| {
20794                buffer.group_until_transaction(transaction, cx);
20795            });
20796        }
20797
20798        if self.text_highlights::<PendingInput>(cx).is_none() {
20799            self.ime_transaction.take();
20800        }
20801    }
20802
20803    pub fn register_action_renderer(
20804        &mut self,
20805        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20806    ) -> Subscription {
20807        let id = self.next_editor_action_id.post_inc();
20808        self.editor_actions
20809            .borrow_mut()
20810            .insert(id, Box::new(listener));
20811
20812        let editor_actions = self.editor_actions.clone();
20813        Subscription::new(move || {
20814            editor_actions.borrow_mut().remove(&id);
20815        })
20816    }
20817
20818    pub fn register_action<A: Action>(
20819        &mut self,
20820        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20821    ) -> Subscription {
20822        let id = self.next_editor_action_id.post_inc();
20823        let listener = Arc::new(listener);
20824        self.editor_actions.borrow_mut().insert(
20825            id,
20826            Box::new(move |_, window, _| {
20827                let listener = listener.clone();
20828                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20829                    let action = action.downcast_ref().unwrap();
20830                    if phase == DispatchPhase::Bubble {
20831                        listener(action, window, cx)
20832                    }
20833                })
20834            }),
20835        );
20836
20837        let editor_actions = self.editor_actions.clone();
20838        Subscription::new(move || {
20839            editor_actions.borrow_mut().remove(&id);
20840        })
20841    }
20842
20843    pub fn file_header_size(&self) -> u32 {
20844        FILE_HEADER_HEIGHT
20845    }
20846
20847    pub fn restore(
20848        &mut self,
20849        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20850        window: &mut Window,
20851        cx: &mut Context<Self>,
20852    ) {
20853        let workspace = self.workspace();
20854        let project = self.project.as_ref();
20855        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20856            let mut tasks = Vec::new();
20857            for (buffer_id, changes) in revert_changes {
20858                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20859                    buffer.update(cx, |buffer, cx| {
20860                        buffer.edit(
20861                            changes
20862                                .into_iter()
20863                                .map(|(range, text)| (range, text.to_string())),
20864                            None,
20865                            cx,
20866                        );
20867                    });
20868
20869                    if let Some(project) =
20870                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20871                    {
20872                        project.update(cx, |project, cx| {
20873                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20874                        })
20875                    }
20876                }
20877            }
20878            tasks
20879        });
20880        cx.spawn_in(window, async move |_, cx| {
20881            for (buffer, task) in save_tasks {
20882                let result = task.await;
20883                if result.is_err() {
20884                    let Some(path) = buffer
20885                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20886                        .ok()
20887                    else {
20888                        continue;
20889                    };
20890                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20891                        let Some(task) = cx
20892                            .update_window_entity(&workspace, |workspace, window, cx| {
20893                                workspace
20894                                    .open_path_preview(path, None, false, false, false, window, cx)
20895                            })
20896                            .ok()
20897                        else {
20898                            continue;
20899                        };
20900                        task.await.log_err();
20901                    }
20902                }
20903            }
20904        })
20905        .detach();
20906        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
20907            selections.refresh()
20908        });
20909    }
20910
20911    pub fn to_pixel_point(
20912        &self,
20913        source: multi_buffer::Anchor,
20914        editor_snapshot: &EditorSnapshot,
20915        window: &mut Window,
20916    ) -> Option<gpui::Point<Pixels>> {
20917        let source_point = source.to_display_point(editor_snapshot);
20918        self.display_to_pixel_point(source_point, editor_snapshot, window)
20919    }
20920
20921    pub fn display_to_pixel_point(
20922        &self,
20923        source: DisplayPoint,
20924        editor_snapshot: &EditorSnapshot,
20925        window: &mut Window,
20926    ) -> Option<gpui::Point<Pixels>> {
20927        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20928        let text_layout_details = self.text_layout_details(window);
20929        let scroll_top = text_layout_details
20930            .scroll_anchor
20931            .scroll_position(editor_snapshot)
20932            .y;
20933
20934        if source.row().as_f32() < scroll_top.floor() {
20935            return None;
20936        }
20937        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20938        let source_y = line_height * (source.row().as_f32() - scroll_top);
20939        Some(gpui::Point::new(source_x, source_y))
20940    }
20941
20942    pub fn has_visible_completions_menu(&self) -> bool {
20943        !self.edit_prediction_preview_is_active()
20944            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20945                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20946            })
20947    }
20948
20949    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20950        if self.mode.is_minimap() {
20951            return;
20952        }
20953        self.addons
20954            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20955    }
20956
20957    pub fn unregister_addon<T: Addon>(&mut self) {
20958        self.addons.remove(&std::any::TypeId::of::<T>());
20959    }
20960
20961    pub fn addon<T: Addon>(&self) -> Option<&T> {
20962        let type_id = std::any::TypeId::of::<T>();
20963        self.addons
20964            .get(&type_id)
20965            .and_then(|item| item.to_any().downcast_ref::<T>())
20966    }
20967
20968    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20969        let type_id = std::any::TypeId::of::<T>();
20970        self.addons
20971            .get_mut(&type_id)
20972            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20973    }
20974
20975    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
20976        let text_layout_details = self.text_layout_details(window);
20977        let style = &text_layout_details.editor_style;
20978        let font_id = window.text_system().resolve_font(&style.text.font());
20979        let font_size = style.text.font_size.to_pixels(window.rem_size());
20980        let line_height = style.text.line_height_in_pixels(window.rem_size());
20981        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20982        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
20983
20984        CharacterDimensions {
20985            em_width,
20986            em_advance,
20987            line_height,
20988        }
20989    }
20990
20991    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20992        self.load_diff_task.clone()
20993    }
20994
20995    fn read_metadata_from_db(
20996        &mut self,
20997        item_id: u64,
20998        workspace_id: WorkspaceId,
20999        window: &mut Window,
21000        cx: &mut Context<Editor>,
21001    ) {
21002        if self.is_singleton(cx)
21003            && !self.mode.is_minimap()
21004            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21005        {
21006            let buffer_snapshot = OnceCell::new();
21007
21008            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
21009                if !folds.is_empty() {
21010                    let snapshot =
21011                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21012                    self.fold_ranges(
21013                        folds
21014                            .into_iter()
21015                            .map(|(start, end)| {
21016                                snapshot.clip_offset(start, Bias::Left)
21017                                    ..snapshot.clip_offset(end, Bias::Right)
21018                            })
21019                            .collect(),
21020                        false,
21021                        window,
21022                        cx,
21023                    );
21024                }
21025            }
21026
21027            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
21028                if !selections.is_empty() {
21029                    let snapshot =
21030                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21031                    // skip adding the initial selection to selection history
21032                    self.selection_history.mode = SelectionHistoryMode::Skipping;
21033                    self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21034                        s.select_ranges(selections.into_iter().map(|(start, end)| {
21035                            snapshot.clip_offset(start, Bias::Left)
21036                                ..snapshot.clip_offset(end, Bias::Right)
21037                        }));
21038                    });
21039                    self.selection_history.mode = SelectionHistoryMode::Normal;
21040                }
21041            };
21042        }
21043
21044        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21045    }
21046
21047    fn update_lsp_data(
21048        &mut self,
21049        ignore_cache: bool,
21050        for_buffer: Option<BufferId>,
21051        window: &mut Window,
21052        cx: &mut Context<'_, Self>,
21053    ) {
21054        self.pull_diagnostics(for_buffer, window, cx);
21055        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21056    }
21057}
21058
21059fn vim_enabled(cx: &App) -> bool {
21060    cx.global::<SettingsStore>()
21061        .raw_user_settings()
21062        .get("vim_mode")
21063        == Some(&serde_json::Value::Bool(true))
21064}
21065
21066fn process_completion_for_edit(
21067    completion: &Completion,
21068    intent: CompletionIntent,
21069    buffer: &Entity<Buffer>,
21070    cursor_position: &text::Anchor,
21071    cx: &mut Context<Editor>,
21072) -> CompletionEdit {
21073    let buffer = buffer.read(cx);
21074    let buffer_snapshot = buffer.snapshot();
21075    let (snippet, new_text) = if completion.is_snippet() {
21076        // Workaround for typescript language server issues so that methods don't expand within
21077        // strings and functions with type expressions. The previous point is used because the query
21078        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21079        let mut snippet_source = completion.new_text.clone();
21080        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21081        previous_point.column = previous_point.column.saturating_sub(1);
21082        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
21083            if scope.prefers_label_for_snippet_in_completion() {
21084                if let Some(label) = completion.label() {
21085                    if matches!(
21086                        completion.kind(),
21087                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21088                    ) {
21089                        snippet_source = label;
21090                    }
21091                }
21092            }
21093        }
21094        match Snippet::parse(&snippet_source).log_err() {
21095            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21096            None => (None, completion.new_text.clone()),
21097        }
21098    } else {
21099        (None, completion.new_text.clone())
21100    };
21101
21102    let mut range_to_replace = {
21103        let replace_range = &completion.replace_range;
21104        if let CompletionSource::Lsp {
21105            insert_range: Some(insert_range),
21106            ..
21107        } = &completion.source
21108        {
21109            debug_assert_eq!(
21110                insert_range.start, replace_range.start,
21111                "insert_range and replace_range should start at the same position"
21112            );
21113            debug_assert!(
21114                insert_range
21115                    .start
21116                    .cmp(&cursor_position, &buffer_snapshot)
21117                    .is_le(),
21118                "insert_range should start before or at cursor position"
21119            );
21120            debug_assert!(
21121                replace_range
21122                    .start
21123                    .cmp(&cursor_position, &buffer_snapshot)
21124                    .is_le(),
21125                "replace_range should start before or at cursor position"
21126            );
21127
21128            let should_replace = match intent {
21129                CompletionIntent::CompleteWithInsert => false,
21130                CompletionIntent::CompleteWithReplace => true,
21131                CompletionIntent::Complete | CompletionIntent::Compose => {
21132                    let insert_mode =
21133                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21134                            .completions
21135                            .lsp_insert_mode;
21136                    match insert_mode {
21137                        LspInsertMode::Insert => false,
21138                        LspInsertMode::Replace => true,
21139                        LspInsertMode::ReplaceSubsequence => {
21140                            let mut text_to_replace = buffer.chars_for_range(
21141                                buffer.anchor_before(replace_range.start)
21142                                    ..buffer.anchor_after(replace_range.end),
21143                            );
21144                            let mut current_needle = text_to_replace.next();
21145                            for haystack_ch in completion.label.text.chars() {
21146                                if let Some(needle_ch) = current_needle {
21147                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
21148                                        current_needle = text_to_replace.next();
21149                                    }
21150                                }
21151                            }
21152                            current_needle.is_none()
21153                        }
21154                        LspInsertMode::ReplaceSuffix => {
21155                            if replace_range
21156                                .end
21157                                .cmp(&cursor_position, &buffer_snapshot)
21158                                .is_gt()
21159                            {
21160                                let range_after_cursor = *cursor_position..replace_range.end;
21161                                let text_after_cursor = buffer
21162                                    .text_for_range(
21163                                        buffer.anchor_before(range_after_cursor.start)
21164                                            ..buffer.anchor_after(range_after_cursor.end),
21165                                    )
21166                                    .collect::<String>()
21167                                    .to_ascii_lowercase();
21168                                completion
21169                                    .label
21170                                    .text
21171                                    .to_ascii_lowercase()
21172                                    .ends_with(&text_after_cursor)
21173                            } else {
21174                                true
21175                            }
21176                        }
21177                    }
21178                }
21179            };
21180
21181            if should_replace {
21182                replace_range.clone()
21183            } else {
21184                insert_range.clone()
21185            }
21186        } else {
21187            replace_range.clone()
21188        }
21189    };
21190
21191    if range_to_replace
21192        .end
21193        .cmp(&cursor_position, &buffer_snapshot)
21194        .is_lt()
21195    {
21196        range_to_replace.end = *cursor_position;
21197    }
21198
21199    CompletionEdit {
21200        new_text,
21201        replace_range: range_to_replace.to_offset(&buffer),
21202        snippet,
21203    }
21204}
21205
21206struct CompletionEdit {
21207    new_text: String,
21208    replace_range: Range<usize>,
21209    snippet: Option<Snippet>,
21210}
21211
21212fn insert_extra_newline_brackets(
21213    buffer: &MultiBufferSnapshot,
21214    range: Range<usize>,
21215    language: &language::LanguageScope,
21216) -> bool {
21217    let leading_whitespace_len = buffer
21218        .reversed_chars_at(range.start)
21219        .take_while(|c| c.is_whitespace() && *c != '\n')
21220        .map(|c| c.len_utf8())
21221        .sum::<usize>();
21222    let trailing_whitespace_len = buffer
21223        .chars_at(range.end)
21224        .take_while(|c| c.is_whitespace() && *c != '\n')
21225        .map(|c| c.len_utf8())
21226        .sum::<usize>();
21227    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21228
21229    language.brackets().any(|(pair, enabled)| {
21230        let pair_start = pair.start.trim_end();
21231        let pair_end = pair.end.trim_start();
21232
21233        enabled
21234            && pair.newline
21235            && buffer.contains_str_at(range.end, pair_end)
21236            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21237    })
21238}
21239
21240fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21241    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21242        [(buffer, range, _)] => (*buffer, range.clone()),
21243        _ => return false,
21244    };
21245    let pair = {
21246        let mut result: Option<BracketMatch> = None;
21247
21248        for pair in buffer
21249            .all_bracket_ranges(range.clone())
21250            .filter(move |pair| {
21251                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21252            })
21253        {
21254            let len = pair.close_range.end - pair.open_range.start;
21255
21256            if let Some(existing) = &result {
21257                let existing_len = existing.close_range.end - existing.open_range.start;
21258                if len > existing_len {
21259                    continue;
21260                }
21261            }
21262
21263            result = Some(pair);
21264        }
21265
21266        result
21267    };
21268    let Some(pair) = pair else {
21269        return false;
21270    };
21271    pair.newline_only
21272        && buffer
21273            .chars_for_range(pair.open_range.end..range.start)
21274            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21275            .all(|c| c.is_whitespace() && c != '\n')
21276}
21277
21278fn update_uncommitted_diff_for_buffer(
21279    editor: Entity<Editor>,
21280    project: &Entity<Project>,
21281    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21282    buffer: Entity<MultiBuffer>,
21283    cx: &mut App,
21284) -> Task<()> {
21285    let mut tasks = Vec::new();
21286    project.update(cx, |project, cx| {
21287        for buffer in buffers {
21288            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21289                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21290            }
21291        }
21292    });
21293    cx.spawn(async move |cx| {
21294        let diffs = future::join_all(tasks).await;
21295        if editor
21296            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21297            .unwrap_or(false)
21298        {
21299            return;
21300        }
21301
21302        buffer
21303            .update(cx, |buffer, cx| {
21304                for diff in diffs.into_iter().flatten() {
21305                    buffer.add_diff(diff, cx);
21306                }
21307            })
21308            .ok();
21309    })
21310}
21311
21312fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21313    let tab_size = tab_size.get() as usize;
21314    let mut width = offset;
21315
21316    for ch in text.chars() {
21317        width += if ch == '\t' {
21318            tab_size - (width % tab_size)
21319        } else {
21320            1
21321        };
21322    }
21323
21324    width - offset
21325}
21326
21327#[cfg(test)]
21328mod tests {
21329    use super::*;
21330
21331    #[test]
21332    fn test_string_size_with_expanded_tabs() {
21333        let nz = |val| NonZeroU32::new(val).unwrap();
21334        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21335        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21336        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21337        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21338        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21339        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21340        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21341        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21342    }
21343}
21344
21345/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21346struct WordBreakingTokenizer<'a> {
21347    input: &'a str,
21348}
21349
21350impl<'a> WordBreakingTokenizer<'a> {
21351    fn new(input: &'a str) -> Self {
21352        Self { input }
21353    }
21354}
21355
21356fn is_char_ideographic(ch: char) -> bool {
21357    use unicode_script::Script::*;
21358    use unicode_script::UnicodeScript;
21359    matches!(ch.script(), Han | Tangut | Yi)
21360}
21361
21362fn is_grapheme_ideographic(text: &str) -> bool {
21363    text.chars().any(is_char_ideographic)
21364}
21365
21366fn is_grapheme_whitespace(text: &str) -> bool {
21367    text.chars().any(|x| x.is_whitespace())
21368}
21369
21370fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21371    text.chars().next().map_or(false, |ch| {
21372        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
21373    })
21374}
21375
21376#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21377enum WordBreakToken<'a> {
21378    Word { token: &'a str, grapheme_len: usize },
21379    InlineWhitespace { token: &'a str, grapheme_len: usize },
21380    Newline,
21381}
21382
21383impl<'a> Iterator for WordBreakingTokenizer<'a> {
21384    /// Yields a span, the count of graphemes in the token, and whether it was
21385    /// whitespace. Note that it also breaks at word boundaries.
21386    type Item = WordBreakToken<'a>;
21387
21388    fn next(&mut self) -> Option<Self::Item> {
21389        use unicode_segmentation::UnicodeSegmentation;
21390        if self.input.is_empty() {
21391            return None;
21392        }
21393
21394        let mut iter = self.input.graphemes(true).peekable();
21395        let mut offset = 0;
21396        let mut grapheme_len = 0;
21397        if let Some(first_grapheme) = iter.next() {
21398            let is_newline = first_grapheme == "\n";
21399            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21400            offset += first_grapheme.len();
21401            grapheme_len += 1;
21402            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21403                if let Some(grapheme) = iter.peek().copied() {
21404                    if should_stay_with_preceding_ideograph(grapheme) {
21405                        offset += grapheme.len();
21406                        grapheme_len += 1;
21407                    }
21408                }
21409            } else {
21410                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21411                let mut next_word_bound = words.peek().copied();
21412                if next_word_bound.map_or(false, |(i, _)| i == 0) {
21413                    next_word_bound = words.next();
21414                }
21415                while let Some(grapheme) = iter.peek().copied() {
21416                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
21417                        break;
21418                    };
21419                    if is_grapheme_whitespace(grapheme) != is_whitespace
21420                        || (grapheme == "\n") != is_newline
21421                    {
21422                        break;
21423                    };
21424                    offset += grapheme.len();
21425                    grapheme_len += 1;
21426                    iter.next();
21427                }
21428            }
21429            let token = &self.input[..offset];
21430            self.input = &self.input[offset..];
21431            if token == "\n" {
21432                Some(WordBreakToken::Newline)
21433            } else if is_whitespace {
21434                Some(WordBreakToken::InlineWhitespace {
21435                    token,
21436                    grapheme_len,
21437                })
21438            } else {
21439                Some(WordBreakToken::Word {
21440                    token,
21441                    grapheme_len,
21442                })
21443            }
21444        } else {
21445            None
21446        }
21447    }
21448}
21449
21450#[test]
21451fn test_word_breaking_tokenizer() {
21452    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21453        ("", &[]),
21454        ("  ", &[whitespace("  ", 2)]),
21455        ("Ʒ", &[word("Ʒ", 1)]),
21456        ("Ǽ", &[word("Ǽ", 1)]),
21457        ("", &[word("", 1)]),
21458        ("⋑⋑", &[word("⋑⋑", 2)]),
21459        (
21460            "原理,进而",
21461            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21462        ),
21463        (
21464            "hello world",
21465            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21466        ),
21467        (
21468            "hello, world",
21469            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21470        ),
21471        (
21472            "  hello world",
21473            &[
21474                whitespace("  ", 2),
21475                word("hello", 5),
21476                whitespace(" ", 1),
21477                word("world", 5),
21478            ],
21479        ),
21480        (
21481            "这是什么 \n 钢笔",
21482            &[
21483                word("", 1),
21484                word("", 1),
21485                word("", 1),
21486                word("", 1),
21487                whitespace(" ", 1),
21488                newline(),
21489                whitespace(" ", 1),
21490                word("", 1),
21491                word("", 1),
21492            ],
21493        ),
21494        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21495    ];
21496
21497    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21498        WordBreakToken::Word {
21499            token,
21500            grapheme_len,
21501        }
21502    }
21503
21504    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21505        WordBreakToken::InlineWhitespace {
21506            token,
21507            grapheme_len,
21508        }
21509    }
21510
21511    fn newline() -> WordBreakToken<'static> {
21512        WordBreakToken::Newline
21513    }
21514
21515    for (input, result) in tests {
21516        assert_eq!(
21517            WordBreakingTokenizer::new(input)
21518                .collect::<Vec<_>>()
21519                .as_slice(),
21520            *result,
21521        );
21522    }
21523}
21524
21525fn wrap_with_prefix(
21526    first_line_prefix: String,
21527    subsequent_lines_prefix: String,
21528    unwrapped_text: String,
21529    wrap_column: usize,
21530    tab_size: NonZeroU32,
21531    preserve_existing_whitespace: bool,
21532) -> String {
21533    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21534    let subsequent_lines_prefix_len =
21535        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21536    let mut wrapped_text = String::new();
21537    let mut current_line = first_line_prefix.clone();
21538    let mut is_first_line = true;
21539
21540    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21541    let mut current_line_len = first_line_prefix_len;
21542    let mut in_whitespace = false;
21543    for token in tokenizer {
21544        let have_preceding_whitespace = in_whitespace;
21545        match token {
21546            WordBreakToken::Word {
21547                token,
21548                grapheme_len,
21549            } => {
21550                in_whitespace = false;
21551                let current_prefix_len = if is_first_line {
21552                    first_line_prefix_len
21553                } else {
21554                    subsequent_lines_prefix_len
21555                };
21556                if current_line_len + grapheme_len > wrap_column
21557                    && current_line_len != current_prefix_len
21558                {
21559                    wrapped_text.push_str(current_line.trim_end());
21560                    wrapped_text.push('\n');
21561                    is_first_line = false;
21562                    current_line = subsequent_lines_prefix.clone();
21563                    current_line_len = subsequent_lines_prefix_len;
21564                }
21565                current_line.push_str(token);
21566                current_line_len += grapheme_len;
21567            }
21568            WordBreakToken::InlineWhitespace {
21569                mut token,
21570                mut grapheme_len,
21571            } => {
21572                in_whitespace = true;
21573                if have_preceding_whitespace && !preserve_existing_whitespace {
21574                    continue;
21575                }
21576                if !preserve_existing_whitespace {
21577                    token = " ";
21578                    grapheme_len = 1;
21579                }
21580                let current_prefix_len = if is_first_line {
21581                    first_line_prefix_len
21582                } else {
21583                    subsequent_lines_prefix_len
21584                };
21585                if current_line_len + grapheme_len > wrap_column {
21586                    wrapped_text.push_str(current_line.trim_end());
21587                    wrapped_text.push('\n');
21588                    is_first_line = false;
21589                    current_line = subsequent_lines_prefix.clone();
21590                    current_line_len = subsequent_lines_prefix_len;
21591                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21592                    current_line.push_str(token);
21593                    current_line_len += grapheme_len;
21594                }
21595            }
21596            WordBreakToken::Newline => {
21597                in_whitespace = true;
21598                let current_prefix_len = if is_first_line {
21599                    first_line_prefix_len
21600                } else {
21601                    subsequent_lines_prefix_len
21602                };
21603                if preserve_existing_whitespace {
21604                    wrapped_text.push_str(current_line.trim_end());
21605                    wrapped_text.push('\n');
21606                    is_first_line = false;
21607                    current_line = subsequent_lines_prefix.clone();
21608                    current_line_len = subsequent_lines_prefix_len;
21609                } else if have_preceding_whitespace {
21610                    continue;
21611                } else if current_line_len + 1 > wrap_column
21612                    && current_line_len != current_prefix_len
21613                {
21614                    wrapped_text.push_str(current_line.trim_end());
21615                    wrapped_text.push('\n');
21616                    is_first_line = false;
21617                    current_line = subsequent_lines_prefix.clone();
21618                    current_line_len = subsequent_lines_prefix_len;
21619                } else if current_line_len != current_prefix_len {
21620                    current_line.push(' ');
21621                    current_line_len += 1;
21622                }
21623            }
21624        }
21625    }
21626
21627    if !current_line.is_empty() {
21628        wrapped_text.push_str(&current_line);
21629    }
21630    wrapped_text
21631}
21632
21633#[test]
21634fn test_wrap_with_prefix() {
21635    assert_eq!(
21636        wrap_with_prefix(
21637            "# ".to_string(),
21638            "# ".to_string(),
21639            "abcdefg".to_string(),
21640            4,
21641            NonZeroU32::new(4).unwrap(),
21642            false,
21643        ),
21644        "# abcdefg"
21645    );
21646    assert_eq!(
21647        wrap_with_prefix(
21648            "".to_string(),
21649            "".to_string(),
21650            "\thello world".to_string(),
21651            8,
21652            NonZeroU32::new(4).unwrap(),
21653            false,
21654        ),
21655        "hello\nworld"
21656    );
21657    assert_eq!(
21658        wrap_with_prefix(
21659            "// ".to_string(),
21660            "// ".to_string(),
21661            "xx \nyy zz aa bb cc".to_string(),
21662            12,
21663            NonZeroU32::new(4).unwrap(),
21664            false,
21665        ),
21666        "// xx yy zz\n// aa bb cc"
21667    );
21668    assert_eq!(
21669        wrap_with_prefix(
21670            String::new(),
21671            String::new(),
21672            "这是什么 \n 钢笔".to_string(),
21673            3,
21674            NonZeroU32::new(4).unwrap(),
21675            false,
21676        ),
21677        "这是什\n么 钢\n"
21678    );
21679}
21680
21681pub trait CollaborationHub {
21682    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21683    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21684    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21685}
21686
21687impl CollaborationHub for Entity<Project> {
21688    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21689        self.read(cx).collaborators()
21690    }
21691
21692    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21693        self.read(cx).user_store().read(cx).participant_indices()
21694    }
21695
21696    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21697        let this = self.read(cx);
21698        let user_ids = this.collaborators().values().map(|c| c.user_id);
21699        this.user_store().read(cx).participant_names(user_ids, cx)
21700    }
21701}
21702
21703pub trait SemanticsProvider {
21704    fn hover(
21705        &self,
21706        buffer: &Entity<Buffer>,
21707        position: text::Anchor,
21708        cx: &mut App,
21709    ) -> Option<Task<Vec<project::Hover>>>;
21710
21711    fn inline_values(
21712        &self,
21713        buffer_handle: Entity<Buffer>,
21714        range: Range<text::Anchor>,
21715        cx: &mut App,
21716    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21717
21718    fn inlay_hints(
21719        &self,
21720        buffer_handle: Entity<Buffer>,
21721        range: Range<text::Anchor>,
21722        cx: &mut App,
21723    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21724
21725    fn resolve_inlay_hint(
21726        &self,
21727        hint: InlayHint,
21728        buffer_handle: Entity<Buffer>,
21729        server_id: LanguageServerId,
21730        cx: &mut App,
21731    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21732
21733    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21734
21735    fn document_highlights(
21736        &self,
21737        buffer: &Entity<Buffer>,
21738        position: text::Anchor,
21739        cx: &mut App,
21740    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21741
21742    fn definitions(
21743        &self,
21744        buffer: &Entity<Buffer>,
21745        position: text::Anchor,
21746        kind: GotoDefinitionKind,
21747        cx: &mut App,
21748    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21749
21750    fn range_for_rename(
21751        &self,
21752        buffer: &Entity<Buffer>,
21753        position: text::Anchor,
21754        cx: &mut App,
21755    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21756
21757    fn perform_rename(
21758        &self,
21759        buffer: &Entity<Buffer>,
21760        position: text::Anchor,
21761        new_name: String,
21762        cx: &mut App,
21763    ) -> Option<Task<Result<ProjectTransaction>>>;
21764}
21765
21766pub trait CompletionProvider {
21767    fn completions(
21768        &self,
21769        excerpt_id: ExcerptId,
21770        buffer: &Entity<Buffer>,
21771        buffer_position: text::Anchor,
21772        trigger: CompletionContext,
21773        window: &mut Window,
21774        cx: &mut Context<Editor>,
21775    ) -> Task<Result<Vec<CompletionResponse>>>;
21776
21777    fn resolve_completions(
21778        &self,
21779        _buffer: Entity<Buffer>,
21780        _completion_indices: Vec<usize>,
21781        _completions: Rc<RefCell<Box<[Completion]>>>,
21782        _cx: &mut Context<Editor>,
21783    ) -> Task<Result<bool>> {
21784        Task::ready(Ok(false))
21785    }
21786
21787    fn apply_additional_edits_for_completion(
21788        &self,
21789        _buffer: Entity<Buffer>,
21790        _completions: Rc<RefCell<Box<[Completion]>>>,
21791        _completion_index: usize,
21792        _push_to_history: bool,
21793        _cx: &mut Context<Editor>,
21794    ) -> Task<Result<Option<language::Transaction>>> {
21795        Task::ready(Ok(None))
21796    }
21797
21798    fn is_completion_trigger(
21799        &self,
21800        buffer: &Entity<Buffer>,
21801        position: language::Anchor,
21802        text: &str,
21803        trigger_in_words: bool,
21804        menu_is_open: bool,
21805        cx: &mut Context<Editor>,
21806    ) -> bool;
21807
21808    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21809
21810    fn sort_completions(&self) -> bool {
21811        true
21812    }
21813
21814    fn filter_completions(&self) -> bool {
21815        true
21816    }
21817}
21818
21819pub trait CodeActionProvider {
21820    fn id(&self) -> Arc<str>;
21821
21822    fn code_actions(
21823        &self,
21824        buffer: &Entity<Buffer>,
21825        range: Range<text::Anchor>,
21826        window: &mut Window,
21827        cx: &mut App,
21828    ) -> Task<Result<Vec<CodeAction>>>;
21829
21830    fn apply_code_action(
21831        &self,
21832        buffer_handle: Entity<Buffer>,
21833        action: CodeAction,
21834        excerpt_id: ExcerptId,
21835        push_to_history: bool,
21836        window: &mut Window,
21837        cx: &mut App,
21838    ) -> Task<Result<ProjectTransaction>>;
21839}
21840
21841impl CodeActionProvider for Entity<Project> {
21842    fn id(&self) -> Arc<str> {
21843        "project".into()
21844    }
21845
21846    fn code_actions(
21847        &self,
21848        buffer: &Entity<Buffer>,
21849        range: Range<text::Anchor>,
21850        _window: &mut Window,
21851        cx: &mut App,
21852    ) -> Task<Result<Vec<CodeAction>>> {
21853        self.update(cx, |project, cx| {
21854            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
21855            let code_actions = project.code_actions(buffer, range, None, cx);
21856            cx.background_spawn(async move {
21857                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
21858                Ok(code_lens_actions
21859                    .context("code lens fetch")?
21860                    .into_iter()
21861                    .chain(code_actions.context("code action fetch")?)
21862                    .collect())
21863            })
21864        })
21865    }
21866
21867    fn apply_code_action(
21868        &self,
21869        buffer_handle: Entity<Buffer>,
21870        action: CodeAction,
21871        _excerpt_id: ExcerptId,
21872        push_to_history: bool,
21873        _window: &mut Window,
21874        cx: &mut App,
21875    ) -> Task<Result<ProjectTransaction>> {
21876        self.update(cx, |project, cx| {
21877            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21878        })
21879    }
21880}
21881
21882fn snippet_completions(
21883    project: &Project,
21884    buffer: &Entity<Buffer>,
21885    buffer_position: text::Anchor,
21886    cx: &mut App,
21887) -> Task<Result<CompletionResponse>> {
21888    let languages = buffer.read(cx).languages_at(buffer_position);
21889    let snippet_store = project.snippets().read(cx);
21890
21891    let scopes: Vec<_> = languages
21892        .iter()
21893        .filter_map(|language| {
21894            let language_name = language.lsp_id();
21895            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21896
21897            if snippets.is_empty() {
21898                None
21899            } else {
21900                Some((language.default_scope(), snippets))
21901            }
21902        })
21903        .collect();
21904
21905    if scopes.is_empty() {
21906        return Task::ready(Ok(CompletionResponse {
21907            completions: vec![],
21908            is_incomplete: false,
21909        }));
21910    }
21911
21912    let snapshot = buffer.read(cx).text_snapshot();
21913    let chars: String = snapshot
21914        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21915        .collect();
21916    let executor = cx.background_executor().clone();
21917
21918    cx.background_spawn(async move {
21919        let mut is_incomplete = false;
21920        let mut completions: Vec<Completion> = Vec::new();
21921        for (scope, snippets) in scopes.into_iter() {
21922            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21923            let mut last_word = chars
21924                .chars()
21925                .take_while(|c| classifier.is_word(*c))
21926                .collect::<String>();
21927            last_word = last_word.chars().rev().collect();
21928
21929            if last_word.is_empty() {
21930                return Ok(CompletionResponse {
21931                    completions: vec![],
21932                    is_incomplete: true,
21933                });
21934            }
21935
21936            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21937            let to_lsp = |point: &text::Anchor| {
21938                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21939                point_to_lsp(end)
21940            };
21941            let lsp_end = to_lsp(&buffer_position);
21942
21943            let candidates = snippets
21944                .iter()
21945                .enumerate()
21946                .flat_map(|(ix, snippet)| {
21947                    snippet
21948                        .prefix
21949                        .iter()
21950                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21951                })
21952                .collect::<Vec<StringMatchCandidate>>();
21953
21954            const MAX_RESULTS: usize = 100;
21955            let mut matches = fuzzy::match_strings(
21956                &candidates,
21957                &last_word,
21958                last_word.chars().any(|c| c.is_uppercase()),
21959                true,
21960                MAX_RESULTS,
21961                &Default::default(),
21962                executor.clone(),
21963            )
21964            .await;
21965
21966            if matches.len() >= MAX_RESULTS {
21967                is_incomplete = true;
21968            }
21969
21970            // Remove all candidates where the query's start does not match the start of any word in the candidate
21971            if let Some(query_start) = last_word.chars().next() {
21972                matches.retain(|string_match| {
21973                    split_words(&string_match.string).any(|word| {
21974                        // Check that the first codepoint of the word as lowercase matches the first
21975                        // codepoint of the query as lowercase
21976                        word.chars()
21977                            .flat_map(|codepoint| codepoint.to_lowercase())
21978                            .zip(query_start.to_lowercase())
21979                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21980                    })
21981                });
21982            }
21983
21984            let matched_strings = matches
21985                .into_iter()
21986                .map(|m| m.string)
21987                .collect::<HashSet<_>>();
21988
21989            completions.extend(snippets.iter().filter_map(|snippet| {
21990                let matching_prefix = snippet
21991                    .prefix
21992                    .iter()
21993                    .find(|prefix| matched_strings.contains(*prefix))?;
21994                let start = as_offset - last_word.len();
21995                let start = snapshot.anchor_before(start);
21996                let range = start..buffer_position;
21997                let lsp_start = to_lsp(&start);
21998                let lsp_range = lsp::Range {
21999                    start: lsp_start,
22000                    end: lsp_end,
22001                };
22002                Some(Completion {
22003                    replace_range: range,
22004                    new_text: snippet.body.clone(),
22005                    source: CompletionSource::Lsp {
22006                        insert_range: None,
22007                        server_id: LanguageServerId(usize::MAX),
22008                        resolved: true,
22009                        lsp_completion: Box::new(lsp::CompletionItem {
22010                            label: snippet.prefix.first().unwrap().clone(),
22011                            kind: Some(CompletionItemKind::SNIPPET),
22012                            label_details: snippet.description.as_ref().map(|description| {
22013                                lsp::CompletionItemLabelDetails {
22014                                    detail: Some(description.clone()),
22015                                    description: None,
22016                                }
22017                            }),
22018                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22019                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22020                                lsp::InsertReplaceEdit {
22021                                    new_text: snippet.body.clone(),
22022                                    insert: lsp_range,
22023                                    replace: lsp_range,
22024                                },
22025                            )),
22026                            filter_text: Some(snippet.body.clone()),
22027                            sort_text: Some(char::MAX.to_string()),
22028                            ..lsp::CompletionItem::default()
22029                        }),
22030                        lsp_defaults: None,
22031                    },
22032                    label: CodeLabel {
22033                        text: matching_prefix.clone(),
22034                        runs: Vec::new(),
22035                        filter_range: 0..matching_prefix.len(),
22036                    },
22037                    icon_path: None,
22038                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22039                        single_line: snippet.name.clone().into(),
22040                        plain_text: snippet
22041                            .description
22042                            .clone()
22043                            .map(|description| description.into()),
22044                    }),
22045                    insert_text_mode: None,
22046                    confirm: None,
22047                })
22048            }))
22049        }
22050
22051        Ok(CompletionResponse {
22052            completions,
22053            is_incomplete,
22054        })
22055    })
22056}
22057
22058impl CompletionProvider for Entity<Project> {
22059    fn completions(
22060        &self,
22061        _excerpt_id: ExcerptId,
22062        buffer: &Entity<Buffer>,
22063        buffer_position: text::Anchor,
22064        options: CompletionContext,
22065        _window: &mut Window,
22066        cx: &mut Context<Editor>,
22067    ) -> Task<Result<Vec<CompletionResponse>>> {
22068        self.update(cx, |project, cx| {
22069            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22070            let project_completions = project.completions(buffer, buffer_position, options, cx);
22071            cx.background_spawn(async move {
22072                let mut responses = project_completions.await?;
22073                let snippets = snippets.await?;
22074                if !snippets.completions.is_empty() {
22075                    responses.push(snippets);
22076                }
22077                Ok(responses)
22078            })
22079        })
22080    }
22081
22082    fn resolve_completions(
22083        &self,
22084        buffer: Entity<Buffer>,
22085        completion_indices: Vec<usize>,
22086        completions: Rc<RefCell<Box<[Completion]>>>,
22087        cx: &mut Context<Editor>,
22088    ) -> Task<Result<bool>> {
22089        self.update(cx, |project, cx| {
22090            project.lsp_store().update(cx, |lsp_store, cx| {
22091                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22092            })
22093        })
22094    }
22095
22096    fn apply_additional_edits_for_completion(
22097        &self,
22098        buffer: Entity<Buffer>,
22099        completions: Rc<RefCell<Box<[Completion]>>>,
22100        completion_index: usize,
22101        push_to_history: bool,
22102        cx: &mut Context<Editor>,
22103    ) -> Task<Result<Option<language::Transaction>>> {
22104        self.update(cx, |project, cx| {
22105            project.lsp_store().update(cx, |lsp_store, cx| {
22106                lsp_store.apply_additional_edits_for_completion(
22107                    buffer,
22108                    completions,
22109                    completion_index,
22110                    push_to_history,
22111                    cx,
22112                )
22113            })
22114        })
22115    }
22116
22117    fn is_completion_trigger(
22118        &self,
22119        buffer: &Entity<Buffer>,
22120        position: language::Anchor,
22121        text: &str,
22122        trigger_in_words: bool,
22123        menu_is_open: bool,
22124        cx: &mut Context<Editor>,
22125    ) -> bool {
22126        let mut chars = text.chars();
22127        let char = if let Some(char) = chars.next() {
22128            char
22129        } else {
22130            return false;
22131        };
22132        if chars.next().is_some() {
22133            return false;
22134        }
22135
22136        let buffer = buffer.read(cx);
22137        let snapshot = buffer.snapshot();
22138        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22139            return false;
22140        }
22141        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22142        if trigger_in_words && classifier.is_word(char) {
22143            return true;
22144        }
22145
22146        buffer.completion_triggers().contains(text)
22147    }
22148}
22149
22150impl SemanticsProvider for Entity<Project> {
22151    fn hover(
22152        &self,
22153        buffer: &Entity<Buffer>,
22154        position: text::Anchor,
22155        cx: &mut App,
22156    ) -> Option<Task<Vec<project::Hover>>> {
22157        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22158    }
22159
22160    fn document_highlights(
22161        &self,
22162        buffer: &Entity<Buffer>,
22163        position: text::Anchor,
22164        cx: &mut App,
22165    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22166        Some(self.update(cx, |project, cx| {
22167            project.document_highlights(buffer, position, cx)
22168        }))
22169    }
22170
22171    fn definitions(
22172        &self,
22173        buffer: &Entity<Buffer>,
22174        position: text::Anchor,
22175        kind: GotoDefinitionKind,
22176        cx: &mut App,
22177    ) -> Option<Task<Result<Vec<LocationLink>>>> {
22178        Some(self.update(cx, |project, cx| match kind {
22179            GotoDefinitionKind::Symbol => project.definitions(&buffer, position, cx),
22180            GotoDefinitionKind::Declaration => project.declarations(&buffer, position, cx),
22181            GotoDefinitionKind::Type => project.type_definitions(&buffer, position, cx),
22182            GotoDefinitionKind::Implementation => project.implementations(&buffer, position, cx),
22183        }))
22184    }
22185
22186    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22187        // TODO: make this work for remote projects
22188        self.update(cx, |project, cx| {
22189            if project
22190                .active_debug_session(cx)
22191                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22192            {
22193                return true;
22194            }
22195
22196            buffer.update(cx, |buffer, cx| {
22197                project.any_language_server_supports_inlay_hints(buffer, cx)
22198            })
22199        })
22200    }
22201
22202    fn inline_values(
22203        &self,
22204        buffer_handle: Entity<Buffer>,
22205        range: Range<text::Anchor>,
22206        cx: &mut App,
22207    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22208        self.update(cx, |project, cx| {
22209            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22210
22211            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22212        })
22213    }
22214
22215    fn inlay_hints(
22216        &self,
22217        buffer_handle: Entity<Buffer>,
22218        range: Range<text::Anchor>,
22219        cx: &mut App,
22220    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22221        Some(self.update(cx, |project, cx| {
22222            project.inlay_hints(buffer_handle, range, cx)
22223        }))
22224    }
22225
22226    fn resolve_inlay_hint(
22227        &self,
22228        hint: InlayHint,
22229        buffer_handle: Entity<Buffer>,
22230        server_id: LanguageServerId,
22231        cx: &mut App,
22232    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22233        Some(self.update(cx, |project, cx| {
22234            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22235        }))
22236    }
22237
22238    fn range_for_rename(
22239        &self,
22240        buffer: &Entity<Buffer>,
22241        position: text::Anchor,
22242        cx: &mut App,
22243    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22244        Some(self.update(cx, |project, cx| {
22245            let buffer = buffer.clone();
22246            let task = project.prepare_rename(buffer.clone(), position, cx);
22247            cx.spawn(async move |_, cx| {
22248                Ok(match task.await? {
22249                    PrepareRenameResponse::Success(range) => Some(range),
22250                    PrepareRenameResponse::InvalidPosition => None,
22251                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22252                        // Fallback on using TreeSitter info to determine identifier range
22253                        buffer.read_with(cx, |buffer, _| {
22254                            let snapshot = buffer.snapshot();
22255                            let (range, kind) = snapshot.surrounding_word(position, false);
22256                            if kind != Some(CharKind::Word) {
22257                                return None;
22258                            }
22259                            Some(
22260                                snapshot.anchor_before(range.start)
22261                                    ..snapshot.anchor_after(range.end),
22262                            )
22263                        })?
22264                    }
22265                })
22266            })
22267        }))
22268    }
22269
22270    fn perform_rename(
22271        &self,
22272        buffer: &Entity<Buffer>,
22273        position: text::Anchor,
22274        new_name: String,
22275        cx: &mut App,
22276    ) -> Option<Task<Result<ProjectTransaction>>> {
22277        Some(self.update(cx, |project, cx| {
22278            project.perform_rename(buffer.clone(), position, new_name, cx)
22279        }))
22280    }
22281}
22282
22283fn inlay_hint_settings(
22284    location: Anchor,
22285    snapshot: &MultiBufferSnapshot,
22286    cx: &mut Context<Editor>,
22287) -> InlayHintSettings {
22288    let file = snapshot.file_at(location);
22289    let language = snapshot.language_at(location).map(|l| l.name());
22290    language_settings(language, file, cx).inlay_hints
22291}
22292
22293fn consume_contiguous_rows(
22294    contiguous_row_selections: &mut Vec<Selection<Point>>,
22295    selection: &Selection<Point>,
22296    display_map: &DisplaySnapshot,
22297    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22298) -> (MultiBufferRow, MultiBufferRow) {
22299    contiguous_row_selections.push(selection.clone());
22300    let start_row = starting_row(selection, display_map);
22301    let mut end_row = ending_row(selection, display_map);
22302
22303    while let Some(next_selection) = selections.peek() {
22304        if next_selection.start.row <= end_row.0 {
22305            end_row = ending_row(next_selection, display_map);
22306            contiguous_row_selections.push(selections.next().unwrap().clone());
22307        } else {
22308            break;
22309        }
22310    }
22311    (start_row, end_row)
22312}
22313
22314fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22315    if selection.start.column > 0 {
22316        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22317    } else {
22318        MultiBufferRow(selection.start.row)
22319    }
22320}
22321
22322fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22323    if next_selection.end.column > 0 || next_selection.is_empty() {
22324        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22325    } else {
22326        MultiBufferRow(next_selection.end.row)
22327    }
22328}
22329
22330impl EditorSnapshot {
22331    pub fn remote_selections_in_range<'a>(
22332        &'a self,
22333        range: &'a Range<Anchor>,
22334        collaboration_hub: &dyn CollaborationHub,
22335        cx: &'a App,
22336    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22337        let participant_names = collaboration_hub.user_names(cx);
22338        let participant_indices = collaboration_hub.user_participant_indices(cx);
22339        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22340        let collaborators_by_replica_id = collaborators_by_peer_id
22341            .values()
22342            .map(|collaborator| (collaborator.replica_id, collaborator))
22343            .collect::<HashMap<_, _>>();
22344        self.buffer_snapshot
22345            .selections_in_range(range, false)
22346            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22347                if replica_id == AGENT_REPLICA_ID {
22348                    Some(RemoteSelection {
22349                        replica_id,
22350                        selection,
22351                        cursor_shape,
22352                        line_mode,
22353                        collaborator_id: CollaboratorId::Agent,
22354                        user_name: Some("Agent".into()),
22355                        color: cx.theme().players().agent(),
22356                    })
22357                } else {
22358                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22359                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22360                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22361                    Some(RemoteSelection {
22362                        replica_id,
22363                        selection,
22364                        cursor_shape,
22365                        line_mode,
22366                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22367                        user_name,
22368                        color: if let Some(index) = participant_index {
22369                            cx.theme().players().color_for_participant(index.0)
22370                        } else {
22371                            cx.theme().players().absent()
22372                        },
22373                    })
22374                }
22375            })
22376    }
22377
22378    pub fn hunks_for_ranges(
22379        &self,
22380        ranges: impl IntoIterator<Item = Range<Point>>,
22381    ) -> Vec<MultiBufferDiffHunk> {
22382        let mut hunks = Vec::new();
22383        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22384            HashMap::default();
22385        for query_range in ranges {
22386            let query_rows =
22387                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22388            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22389                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22390            ) {
22391                // Include deleted hunks that are adjacent to the query range, because
22392                // otherwise they would be missed.
22393                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22394                if hunk.status().is_deleted() {
22395                    intersects_range |= hunk.row_range.start == query_rows.end;
22396                    intersects_range |= hunk.row_range.end == query_rows.start;
22397                }
22398                if intersects_range {
22399                    if !processed_buffer_rows
22400                        .entry(hunk.buffer_id)
22401                        .or_default()
22402                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22403                    {
22404                        continue;
22405                    }
22406                    hunks.push(hunk);
22407                }
22408            }
22409        }
22410
22411        hunks
22412    }
22413
22414    fn display_diff_hunks_for_rows<'a>(
22415        &'a self,
22416        display_rows: Range<DisplayRow>,
22417        folded_buffers: &'a HashSet<BufferId>,
22418    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22419        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22420        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22421
22422        self.buffer_snapshot
22423            .diff_hunks_in_range(buffer_start..buffer_end)
22424            .filter_map(|hunk| {
22425                if folded_buffers.contains(&hunk.buffer_id) {
22426                    return None;
22427                }
22428
22429                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22430                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22431
22432                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22433                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22434
22435                let display_hunk = if hunk_display_start.column() != 0 {
22436                    DisplayDiffHunk::Folded {
22437                        display_row: hunk_display_start.row(),
22438                    }
22439                } else {
22440                    let mut end_row = hunk_display_end.row();
22441                    if hunk_display_end.column() > 0 {
22442                        end_row.0 += 1;
22443                    }
22444                    let is_created_file = hunk.is_created_file();
22445                    DisplayDiffHunk::Unfolded {
22446                        status: hunk.status(),
22447                        diff_base_byte_range: hunk.diff_base_byte_range,
22448                        display_row_range: hunk_display_start.row()..end_row,
22449                        multi_buffer_range: Anchor::range_in_buffer(
22450                            hunk.excerpt_id,
22451                            hunk.buffer_id,
22452                            hunk.buffer_range,
22453                        ),
22454                        is_created_file,
22455                    }
22456                };
22457
22458                Some(display_hunk)
22459            })
22460    }
22461
22462    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22463        self.display_snapshot.buffer_snapshot.language_at(position)
22464    }
22465
22466    pub fn is_focused(&self) -> bool {
22467        self.is_focused
22468    }
22469
22470    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22471        self.placeholder_text.as_ref()
22472    }
22473
22474    pub fn scroll_position(&self) -> gpui::Point<f32> {
22475        self.scroll_anchor.scroll_position(&self.display_snapshot)
22476    }
22477
22478    fn gutter_dimensions(
22479        &self,
22480        font_id: FontId,
22481        font_size: Pixels,
22482        max_line_number_width: Pixels,
22483        cx: &App,
22484    ) -> Option<GutterDimensions> {
22485        if !self.show_gutter {
22486            return None;
22487        }
22488
22489        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22490        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22491
22492        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22493            matches!(
22494                ProjectSettings::get_global(cx).git.git_gutter,
22495                Some(GitGutterSetting::TrackedFiles)
22496            )
22497        });
22498        let gutter_settings = EditorSettings::get_global(cx).gutter;
22499        let show_line_numbers = self
22500            .show_line_numbers
22501            .unwrap_or(gutter_settings.line_numbers);
22502        let line_gutter_width = if show_line_numbers {
22503            // Avoid flicker-like gutter resizes when the line number gains another digit by
22504            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22505            let min_width_for_number_on_gutter =
22506                ch_advance * gutter_settings.min_line_number_digits as f32;
22507            max_line_number_width.max(min_width_for_number_on_gutter)
22508        } else {
22509            0.0.into()
22510        };
22511
22512        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22513        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22514
22515        let git_blame_entries_width =
22516            self.git_blame_gutter_max_author_length
22517                .map(|max_author_length| {
22518                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22519                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22520
22521                    /// The number of characters to dedicate to gaps and margins.
22522                    const SPACING_WIDTH: usize = 4;
22523
22524                    let max_char_count = max_author_length.min(renderer.max_author_length())
22525                        + ::git::SHORT_SHA_LENGTH
22526                        + MAX_RELATIVE_TIMESTAMP.len()
22527                        + SPACING_WIDTH;
22528
22529                    ch_advance * max_char_count
22530                });
22531
22532        let is_singleton = self.buffer_snapshot.is_singleton();
22533
22534        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22535        left_padding += if !is_singleton {
22536            ch_width * 4.0
22537        } else if show_runnables || show_breakpoints {
22538            ch_width * 3.0
22539        } else if show_git_gutter && show_line_numbers {
22540            ch_width * 2.0
22541        } else if show_git_gutter || show_line_numbers {
22542            ch_width
22543        } else {
22544            px(0.)
22545        };
22546
22547        let shows_folds = is_singleton && gutter_settings.folds;
22548
22549        let right_padding = if shows_folds && show_line_numbers {
22550            ch_width * 4.0
22551        } else if shows_folds || (!is_singleton && show_line_numbers) {
22552            ch_width * 3.0
22553        } else if show_line_numbers {
22554            ch_width
22555        } else {
22556            px(0.)
22557        };
22558
22559        Some(GutterDimensions {
22560            left_padding,
22561            right_padding,
22562            width: line_gutter_width + left_padding + right_padding,
22563            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22564            git_blame_entries_width,
22565        })
22566    }
22567
22568    pub fn render_crease_toggle(
22569        &self,
22570        buffer_row: MultiBufferRow,
22571        row_contains_cursor: bool,
22572        editor: Entity<Editor>,
22573        window: &mut Window,
22574        cx: &mut App,
22575    ) -> Option<AnyElement> {
22576        let folded = self.is_line_folded(buffer_row);
22577        let mut is_foldable = false;
22578
22579        if let Some(crease) = self
22580            .crease_snapshot
22581            .query_row(buffer_row, &self.buffer_snapshot)
22582        {
22583            is_foldable = true;
22584            match crease {
22585                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22586                    if let Some(render_toggle) = render_toggle {
22587                        let toggle_callback =
22588                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22589                                if folded {
22590                                    editor.update(cx, |editor, cx| {
22591                                        editor.fold_at(buffer_row, window, cx)
22592                                    });
22593                                } else {
22594                                    editor.update(cx, |editor, cx| {
22595                                        editor.unfold_at(buffer_row, window, cx)
22596                                    });
22597                                }
22598                            });
22599                        return Some((render_toggle)(
22600                            buffer_row,
22601                            folded,
22602                            toggle_callback,
22603                            window,
22604                            cx,
22605                        ));
22606                    }
22607                }
22608            }
22609        }
22610
22611        is_foldable |= self.starts_indent(buffer_row);
22612
22613        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22614            Some(
22615                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22616                    .toggle_state(folded)
22617                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22618                        if folded {
22619                            this.unfold_at(buffer_row, window, cx);
22620                        } else {
22621                            this.fold_at(buffer_row, window, cx);
22622                        }
22623                    }))
22624                    .into_any_element(),
22625            )
22626        } else {
22627            None
22628        }
22629    }
22630
22631    pub fn render_crease_trailer(
22632        &self,
22633        buffer_row: MultiBufferRow,
22634        window: &mut Window,
22635        cx: &mut App,
22636    ) -> Option<AnyElement> {
22637        let folded = self.is_line_folded(buffer_row);
22638        if let Crease::Inline { render_trailer, .. } = self
22639            .crease_snapshot
22640            .query_row(buffer_row, &self.buffer_snapshot)?
22641        {
22642            let render_trailer = render_trailer.as_ref()?;
22643            Some(render_trailer(buffer_row, folded, window, cx))
22644        } else {
22645            None
22646        }
22647    }
22648}
22649
22650impl Deref for EditorSnapshot {
22651    type Target = DisplaySnapshot;
22652
22653    fn deref(&self) -> &Self::Target {
22654        &self.display_snapshot
22655    }
22656}
22657
22658#[derive(Clone, Debug, PartialEq, Eq)]
22659pub enum EditorEvent {
22660    InputIgnored {
22661        text: Arc<str>,
22662    },
22663    InputHandled {
22664        utf16_range_to_replace: Option<Range<isize>>,
22665        text: Arc<str>,
22666    },
22667    ExcerptsAdded {
22668        buffer: Entity<Buffer>,
22669        predecessor: ExcerptId,
22670        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22671    },
22672    ExcerptsRemoved {
22673        ids: Vec<ExcerptId>,
22674        removed_buffer_ids: Vec<BufferId>,
22675    },
22676    BufferFoldToggled {
22677        ids: Vec<ExcerptId>,
22678        folded: bool,
22679    },
22680    ExcerptsEdited {
22681        ids: Vec<ExcerptId>,
22682    },
22683    ExcerptsExpanded {
22684        ids: Vec<ExcerptId>,
22685    },
22686    BufferEdited,
22687    Edited {
22688        transaction_id: clock::Lamport,
22689    },
22690    Reparsed(BufferId),
22691    Focused,
22692    FocusedIn,
22693    Blurred,
22694    DirtyChanged,
22695    Saved,
22696    TitleChanged,
22697    DiffBaseChanged,
22698    SelectionsChanged {
22699        local: bool,
22700    },
22701    ScrollPositionChanged {
22702        local: bool,
22703        autoscroll: bool,
22704    },
22705    Closed,
22706    TransactionUndone {
22707        transaction_id: clock::Lamport,
22708    },
22709    TransactionBegun {
22710        transaction_id: clock::Lamport,
22711    },
22712    Reloaded,
22713    CursorShapeChanged,
22714    PushedToNavHistory {
22715        anchor: Anchor,
22716        is_deactivate: bool,
22717    },
22718}
22719
22720impl EventEmitter<EditorEvent> for Editor {}
22721
22722impl Focusable for Editor {
22723    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22724        self.focus_handle.clone()
22725    }
22726}
22727
22728impl Render for Editor {
22729    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22730        let settings = ThemeSettings::get_global(cx);
22731
22732        let mut text_style = match self.mode {
22733            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22734                color: cx.theme().colors().editor_foreground,
22735                font_family: settings.ui_font.family.clone(),
22736                font_features: settings.ui_font.features.clone(),
22737                font_fallbacks: settings.ui_font.fallbacks.clone(),
22738                font_size: rems(0.875).into(),
22739                font_weight: settings.ui_font.weight,
22740                line_height: relative(settings.buffer_line_height.value()),
22741                ..Default::default()
22742            },
22743            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22744                color: cx.theme().colors().editor_foreground,
22745                font_family: settings.buffer_font.family.clone(),
22746                font_features: settings.buffer_font.features.clone(),
22747                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22748                font_size: settings.buffer_font_size(cx).into(),
22749                font_weight: settings.buffer_font.weight,
22750                line_height: relative(settings.buffer_line_height.value()),
22751                ..Default::default()
22752            },
22753        };
22754        if let Some(text_style_refinement) = &self.text_style_refinement {
22755            text_style.refine(text_style_refinement)
22756        }
22757
22758        let background = match self.mode {
22759            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22760            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22761            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22762            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22763        };
22764
22765        EditorElement::new(
22766            &cx.entity(),
22767            EditorStyle {
22768                background,
22769                border: cx.theme().colors().border,
22770                local_player: cx.theme().players().local(),
22771                text: text_style,
22772                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22773                syntax: cx.theme().syntax().clone(),
22774                status: cx.theme().status().clone(),
22775                inlay_hints_style: make_inlay_hints_style(cx),
22776                inline_completion_styles: make_suggestion_styles(cx),
22777                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22778                show_underlines: self.diagnostics_enabled(),
22779            },
22780        )
22781    }
22782}
22783
22784impl EntityInputHandler for Editor {
22785    fn text_for_range(
22786        &mut self,
22787        range_utf16: Range<usize>,
22788        adjusted_range: &mut Option<Range<usize>>,
22789        _: &mut Window,
22790        cx: &mut Context<Self>,
22791    ) -> Option<String> {
22792        let snapshot = self.buffer.read(cx).read(cx);
22793        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22794        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22795        if (start.0..end.0) != range_utf16 {
22796            adjusted_range.replace(start.0..end.0);
22797        }
22798        Some(snapshot.text_for_range(start..end).collect())
22799    }
22800
22801    fn selected_text_range(
22802        &mut self,
22803        ignore_disabled_input: bool,
22804        _: &mut Window,
22805        cx: &mut Context<Self>,
22806    ) -> Option<UTF16Selection> {
22807        // Prevent the IME menu from appearing when holding down an alphabetic key
22808        // while input is disabled.
22809        if !ignore_disabled_input && !self.input_enabled {
22810            return None;
22811        }
22812
22813        let selection = self.selections.newest::<OffsetUtf16>(cx);
22814        let range = selection.range();
22815
22816        Some(UTF16Selection {
22817            range: range.start.0..range.end.0,
22818            reversed: selection.reversed,
22819        })
22820    }
22821
22822    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22823        let snapshot = self.buffer.read(cx).read(cx);
22824        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22825        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22826    }
22827
22828    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22829        self.clear_highlights::<InputComposition>(cx);
22830        self.ime_transaction.take();
22831    }
22832
22833    fn replace_text_in_range(
22834        &mut self,
22835        range_utf16: Option<Range<usize>>,
22836        text: &str,
22837        window: &mut Window,
22838        cx: &mut Context<Self>,
22839    ) {
22840        if !self.input_enabled {
22841            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22842            return;
22843        }
22844
22845        self.transact(window, cx, |this, window, cx| {
22846            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22847                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22848                Some(this.selection_replacement_ranges(range_utf16, cx))
22849            } else {
22850                this.marked_text_ranges(cx)
22851            };
22852
22853            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22854                let newest_selection_id = this.selections.newest_anchor().id;
22855                this.selections
22856                    .all::<OffsetUtf16>(cx)
22857                    .iter()
22858                    .zip(ranges_to_replace.iter())
22859                    .find_map(|(selection, range)| {
22860                        if selection.id == newest_selection_id {
22861                            Some(
22862                                (range.start.0 as isize - selection.head().0 as isize)
22863                                    ..(range.end.0 as isize - selection.head().0 as isize),
22864                            )
22865                        } else {
22866                            None
22867                        }
22868                    })
22869            });
22870
22871            cx.emit(EditorEvent::InputHandled {
22872                utf16_range_to_replace: range_to_replace,
22873                text: text.into(),
22874            });
22875
22876            if let Some(new_selected_ranges) = new_selected_ranges {
22877                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22878                    selections.select_ranges(new_selected_ranges)
22879                });
22880                this.backspace(&Default::default(), window, cx);
22881            }
22882
22883            this.handle_input(text, window, cx);
22884        });
22885
22886        if let Some(transaction) = self.ime_transaction {
22887            self.buffer.update(cx, |buffer, cx| {
22888                buffer.group_until_transaction(transaction, cx);
22889            });
22890        }
22891
22892        self.unmark_text(window, cx);
22893    }
22894
22895    fn replace_and_mark_text_in_range(
22896        &mut self,
22897        range_utf16: Option<Range<usize>>,
22898        text: &str,
22899        new_selected_range_utf16: Option<Range<usize>>,
22900        window: &mut Window,
22901        cx: &mut Context<Self>,
22902    ) {
22903        if !self.input_enabled {
22904            return;
22905        }
22906
22907        let transaction = self.transact(window, cx, |this, window, cx| {
22908            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22909                let snapshot = this.buffer.read(cx).read(cx);
22910                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22911                    for marked_range in &mut marked_ranges {
22912                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22913                        marked_range.start.0 += relative_range_utf16.start;
22914                        marked_range.start =
22915                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22916                        marked_range.end =
22917                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22918                    }
22919                }
22920                Some(marked_ranges)
22921            } else if let Some(range_utf16) = range_utf16 {
22922                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22923                Some(this.selection_replacement_ranges(range_utf16, cx))
22924            } else {
22925                None
22926            };
22927
22928            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22929                let newest_selection_id = this.selections.newest_anchor().id;
22930                this.selections
22931                    .all::<OffsetUtf16>(cx)
22932                    .iter()
22933                    .zip(ranges_to_replace.iter())
22934                    .find_map(|(selection, range)| {
22935                        if selection.id == newest_selection_id {
22936                            Some(
22937                                (range.start.0 as isize - selection.head().0 as isize)
22938                                    ..(range.end.0 as isize - selection.head().0 as isize),
22939                            )
22940                        } else {
22941                            None
22942                        }
22943                    })
22944            });
22945
22946            cx.emit(EditorEvent::InputHandled {
22947                utf16_range_to_replace: range_to_replace,
22948                text: text.into(),
22949            });
22950
22951            if let Some(ranges) = ranges_to_replace {
22952                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22953                    s.select_ranges(ranges)
22954                });
22955            }
22956
22957            let marked_ranges = {
22958                let snapshot = this.buffer.read(cx).read(cx);
22959                this.selections
22960                    .disjoint_anchors()
22961                    .iter()
22962                    .map(|selection| {
22963                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22964                    })
22965                    .collect::<Vec<_>>()
22966            };
22967
22968            if text.is_empty() {
22969                this.unmark_text(window, cx);
22970            } else {
22971                this.highlight_text::<InputComposition>(
22972                    marked_ranges.clone(),
22973                    HighlightStyle {
22974                        underline: Some(UnderlineStyle {
22975                            thickness: px(1.),
22976                            color: None,
22977                            wavy: false,
22978                        }),
22979                        ..Default::default()
22980                    },
22981                    cx,
22982                );
22983            }
22984
22985            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22986            let use_autoclose = this.use_autoclose;
22987            let use_auto_surround = this.use_auto_surround;
22988            this.set_use_autoclose(false);
22989            this.set_use_auto_surround(false);
22990            this.handle_input(text, window, cx);
22991            this.set_use_autoclose(use_autoclose);
22992            this.set_use_auto_surround(use_auto_surround);
22993
22994            if let Some(new_selected_range) = new_selected_range_utf16 {
22995                let snapshot = this.buffer.read(cx).read(cx);
22996                let new_selected_ranges = marked_ranges
22997                    .into_iter()
22998                    .map(|marked_range| {
22999                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23000                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23001                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23002                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23003                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23004                    })
23005                    .collect::<Vec<_>>();
23006
23007                drop(snapshot);
23008                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23009                    selections.select_ranges(new_selected_ranges)
23010                });
23011            }
23012        });
23013
23014        self.ime_transaction = self.ime_transaction.or(transaction);
23015        if let Some(transaction) = self.ime_transaction {
23016            self.buffer.update(cx, |buffer, cx| {
23017                buffer.group_until_transaction(transaction, cx);
23018            });
23019        }
23020
23021        if self.text_highlights::<InputComposition>(cx).is_none() {
23022            self.ime_transaction.take();
23023        }
23024    }
23025
23026    fn bounds_for_range(
23027        &mut self,
23028        range_utf16: Range<usize>,
23029        element_bounds: gpui::Bounds<Pixels>,
23030        window: &mut Window,
23031        cx: &mut Context<Self>,
23032    ) -> Option<gpui::Bounds<Pixels>> {
23033        let text_layout_details = self.text_layout_details(window);
23034        let CharacterDimensions {
23035            em_width,
23036            em_advance,
23037            line_height,
23038        } = self.character_dimensions(window);
23039
23040        let snapshot = self.snapshot(window, cx);
23041        let scroll_position = snapshot.scroll_position();
23042        let scroll_left = scroll_position.x * em_advance;
23043
23044        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23045        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23046            + self.gutter_dimensions.full_width();
23047        let y = line_height * (start.row().as_f32() - scroll_position.y);
23048
23049        Some(Bounds {
23050            origin: element_bounds.origin + point(x, y),
23051            size: size(em_width, line_height),
23052        })
23053    }
23054
23055    fn character_index_for_point(
23056        &mut self,
23057        point: gpui::Point<Pixels>,
23058        _window: &mut Window,
23059        _cx: &mut Context<Self>,
23060    ) -> Option<usize> {
23061        let position_map = self.last_position_map.as_ref()?;
23062        if !position_map.text_hitbox.contains(&point) {
23063            return None;
23064        }
23065        let display_point = position_map.point_for_position(point).previous_valid;
23066        let anchor = position_map
23067            .snapshot
23068            .display_point_to_anchor(display_point, Bias::Left);
23069        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23070        Some(utf16_offset.0)
23071    }
23072}
23073
23074trait SelectionExt {
23075    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23076    fn spanned_rows(
23077        &self,
23078        include_end_if_at_line_start: bool,
23079        map: &DisplaySnapshot,
23080    ) -> Range<MultiBufferRow>;
23081}
23082
23083impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23084    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23085        let start = self
23086            .start
23087            .to_point(&map.buffer_snapshot)
23088            .to_display_point(map);
23089        let end = self
23090            .end
23091            .to_point(&map.buffer_snapshot)
23092            .to_display_point(map);
23093        if self.reversed {
23094            end..start
23095        } else {
23096            start..end
23097        }
23098    }
23099
23100    fn spanned_rows(
23101        &self,
23102        include_end_if_at_line_start: bool,
23103        map: &DisplaySnapshot,
23104    ) -> Range<MultiBufferRow> {
23105        let start = self.start.to_point(&map.buffer_snapshot);
23106        let mut end = self.end.to_point(&map.buffer_snapshot);
23107        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23108            end.row -= 1;
23109        }
23110
23111        let buffer_start = map.prev_line_boundary(start).0;
23112        let buffer_end = map.next_line_boundary(end).0;
23113        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23114    }
23115}
23116
23117impl<T: InvalidationRegion> InvalidationStack<T> {
23118    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23119    where
23120        S: Clone + ToOffset,
23121    {
23122        while let Some(region) = self.last() {
23123            let all_selections_inside_invalidation_ranges =
23124                if selections.len() == region.ranges().len() {
23125                    selections
23126                        .iter()
23127                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23128                        .all(|(selection, invalidation_range)| {
23129                            let head = selection.head().to_offset(buffer);
23130                            invalidation_range.start <= head && invalidation_range.end >= head
23131                        })
23132                } else {
23133                    false
23134                };
23135
23136            if all_selections_inside_invalidation_ranges {
23137                break;
23138            } else {
23139                self.pop();
23140            }
23141        }
23142    }
23143}
23144
23145impl<T> Default for InvalidationStack<T> {
23146    fn default() -> Self {
23147        Self(Default::default())
23148    }
23149}
23150
23151impl<T> Deref for InvalidationStack<T> {
23152    type Target = Vec<T>;
23153
23154    fn deref(&self) -> &Self::Target {
23155        &self.0
23156    }
23157}
23158
23159impl<T> DerefMut for InvalidationStack<T> {
23160    fn deref_mut(&mut self) -> &mut Self::Target {
23161        &mut self.0
23162    }
23163}
23164
23165impl InvalidationRegion for SnippetState {
23166    fn ranges(&self) -> &[Range<Anchor>] {
23167        &self.ranges[self.active_index]
23168    }
23169}
23170
23171fn inline_completion_edit_text(
23172    current_snapshot: &BufferSnapshot,
23173    edits: &[(Range<Anchor>, String)],
23174    edit_preview: &EditPreview,
23175    include_deletions: bool,
23176    cx: &App,
23177) -> HighlightedText {
23178    let edits = edits
23179        .iter()
23180        .map(|(anchor, text)| {
23181            (
23182                anchor.start.text_anchor..anchor.end.text_anchor,
23183                text.clone(),
23184            )
23185        })
23186        .collect::<Vec<_>>();
23187
23188    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23189}
23190
23191pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23192    match severity {
23193        lsp::DiagnosticSeverity::ERROR => colors.error,
23194        lsp::DiagnosticSeverity::WARNING => colors.warning,
23195        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23196        lsp::DiagnosticSeverity::HINT => colors.info,
23197        _ => colors.ignored,
23198    }
23199}
23200
23201pub fn styled_runs_for_code_label<'a>(
23202    label: &'a CodeLabel,
23203    syntax_theme: &'a theme::SyntaxTheme,
23204) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23205    let fade_out = HighlightStyle {
23206        fade_out: Some(0.35),
23207        ..Default::default()
23208    };
23209
23210    let mut prev_end = label.filter_range.end;
23211    label
23212        .runs
23213        .iter()
23214        .enumerate()
23215        .flat_map(move |(ix, (range, highlight_id))| {
23216            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23217                style
23218            } else {
23219                return Default::default();
23220            };
23221            let mut muted_style = style;
23222            muted_style.highlight(fade_out);
23223
23224            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23225            if range.start >= label.filter_range.end {
23226                if range.start > prev_end {
23227                    runs.push((prev_end..range.start, fade_out));
23228                }
23229                runs.push((range.clone(), muted_style));
23230            } else if range.end <= label.filter_range.end {
23231                runs.push((range.clone(), style));
23232            } else {
23233                runs.push((range.start..label.filter_range.end, style));
23234                runs.push((label.filter_range.end..range.end, muted_style));
23235            }
23236            prev_end = cmp::max(prev_end, range.end);
23237
23238            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23239                runs.push((prev_end..label.text.len(), fade_out));
23240            }
23241
23242            runs
23243        })
23244}
23245
23246pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23247    let mut prev_index = 0;
23248    let mut prev_codepoint: Option<char> = None;
23249    text.char_indices()
23250        .chain([(text.len(), '\0')])
23251        .filter_map(move |(index, codepoint)| {
23252            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23253            let is_boundary = index == text.len()
23254                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23255                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23256            if is_boundary {
23257                let chunk = &text[prev_index..index];
23258                prev_index = index;
23259                Some(chunk)
23260            } else {
23261                None
23262            }
23263        })
23264}
23265
23266pub trait RangeToAnchorExt: Sized {
23267    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23268
23269    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23270        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23271        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23272    }
23273}
23274
23275impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23276    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23277        let start_offset = self.start.to_offset(snapshot);
23278        let end_offset = self.end.to_offset(snapshot);
23279        if start_offset == end_offset {
23280            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23281        } else {
23282            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23283        }
23284    }
23285}
23286
23287pub trait RowExt {
23288    fn as_f32(&self) -> f32;
23289
23290    fn next_row(&self) -> Self;
23291
23292    fn previous_row(&self) -> Self;
23293
23294    fn minus(&self, other: Self) -> u32;
23295}
23296
23297impl RowExt for DisplayRow {
23298    fn as_f32(&self) -> f32 {
23299        self.0 as f32
23300    }
23301
23302    fn next_row(&self) -> Self {
23303        Self(self.0 + 1)
23304    }
23305
23306    fn previous_row(&self) -> Self {
23307        Self(self.0.saturating_sub(1))
23308    }
23309
23310    fn minus(&self, other: Self) -> u32 {
23311        self.0 - other.0
23312    }
23313}
23314
23315impl RowExt for MultiBufferRow {
23316    fn as_f32(&self) -> f32 {
23317        self.0 as f32
23318    }
23319
23320    fn next_row(&self) -> Self {
23321        Self(self.0 + 1)
23322    }
23323
23324    fn previous_row(&self) -> Self {
23325        Self(self.0.saturating_sub(1))
23326    }
23327
23328    fn minus(&self, other: Self) -> u32 {
23329        self.0 - other.0
23330    }
23331}
23332
23333trait RowRangeExt {
23334    type Row;
23335
23336    fn len(&self) -> usize;
23337
23338    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23339}
23340
23341impl RowRangeExt for Range<MultiBufferRow> {
23342    type Row = MultiBufferRow;
23343
23344    fn len(&self) -> usize {
23345        (self.end.0 - self.start.0) as usize
23346    }
23347
23348    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23349        (self.start.0..self.end.0).map(MultiBufferRow)
23350    }
23351}
23352
23353impl RowRangeExt for Range<DisplayRow> {
23354    type Row = DisplayRow;
23355
23356    fn len(&self) -> usize {
23357        (self.end.0 - self.start.0) as usize
23358    }
23359
23360    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23361        (self.start.0..self.end.0).map(DisplayRow)
23362    }
23363}
23364
23365/// If select range has more than one line, we
23366/// just point the cursor to range.start.
23367fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23368    if range.start.row == range.end.row {
23369        range
23370    } else {
23371        range.start..range.start
23372    }
23373}
23374pub struct KillRing(ClipboardItem);
23375impl Global for KillRing {}
23376
23377const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23378
23379enum BreakpointPromptEditAction {
23380    Log,
23381    Condition,
23382    HitCondition,
23383}
23384
23385struct BreakpointPromptEditor {
23386    pub(crate) prompt: Entity<Editor>,
23387    editor: WeakEntity<Editor>,
23388    breakpoint_anchor: Anchor,
23389    breakpoint: Breakpoint,
23390    edit_action: BreakpointPromptEditAction,
23391    block_ids: HashSet<CustomBlockId>,
23392    editor_margins: Arc<Mutex<EditorMargins>>,
23393    _subscriptions: Vec<Subscription>,
23394}
23395
23396impl BreakpointPromptEditor {
23397    const MAX_LINES: u8 = 4;
23398
23399    fn new(
23400        editor: WeakEntity<Editor>,
23401        breakpoint_anchor: Anchor,
23402        breakpoint: Breakpoint,
23403        edit_action: BreakpointPromptEditAction,
23404        window: &mut Window,
23405        cx: &mut Context<Self>,
23406    ) -> Self {
23407        let base_text = match edit_action {
23408            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23409            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23410            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23411        }
23412        .map(|msg| msg.to_string())
23413        .unwrap_or_default();
23414
23415        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23416        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23417
23418        let prompt = cx.new(|cx| {
23419            let mut prompt = Editor::new(
23420                EditorMode::AutoHeight {
23421                    min_lines: 1,
23422                    max_lines: Some(Self::MAX_LINES as usize),
23423                },
23424                buffer,
23425                None,
23426                window,
23427                cx,
23428            );
23429            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23430            prompt.set_show_cursor_when_unfocused(false, cx);
23431            prompt.set_placeholder_text(
23432                match edit_action {
23433                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23434                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23435                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23436                },
23437                cx,
23438            );
23439
23440            prompt
23441        });
23442
23443        Self {
23444            prompt,
23445            editor,
23446            breakpoint_anchor,
23447            breakpoint,
23448            edit_action,
23449            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23450            block_ids: Default::default(),
23451            _subscriptions: vec![],
23452        }
23453    }
23454
23455    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23456        self.block_ids.extend(block_ids)
23457    }
23458
23459    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23460        if let Some(editor) = self.editor.upgrade() {
23461            let message = self
23462                .prompt
23463                .read(cx)
23464                .buffer
23465                .read(cx)
23466                .as_singleton()
23467                .expect("A multi buffer in breakpoint prompt isn't possible")
23468                .read(cx)
23469                .as_rope()
23470                .to_string();
23471
23472            editor.update(cx, |editor, cx| {
23473                editor.edit_breakpoint_at_anchor(
23474                    self.breakpoint_anchor,
23475                    self.breakpoint.clone(),
23476                    match self.edit_action {
23477                        BreakpointPromptEditAction::Log => {
23478                            BreakpointEditAction::EditLogMessage(message.into())
23479                        }
23480                        BreakpointPromptEditAction::Condition => {
23481                            BreakpointEditAction::EditCondition(message.into())
23482                        }
23483                        BreakpointPromptEditAction::HitCondition => {
23484                            BreakpointEditAction::EditHitCondition(message.into())
23485                        }
23486                    },
23487                    cx,
23488                );
23489
23490                editor.remove_blocks(self.block_ids.clone(), None, cx);
23491                cx.focus_self(window);
23492            });
23493        }
23494    }
23495
23496    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23497        self.editor
23498            .update(cx, |editor, cx| {
23499                editor.remove_blocks(self.block_ids.clone(), None, cx);
23500                window.focus(&editor.focus_handle);
23501            })
23502            .log_err();
23503    }
23504
23505    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23506        let settings = ThemeSettings::get_global(cx);
23507        let text_style = TextStyle {
23508            color: if self.prompt.read(cx).read_only(cx) {
23509                cx.theme().colors().text_disabled
23510            } else {
23511                cx.theme().colors().text
23512            },
23513            font_family: settings.buffer_font.family.clone(),
23514            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23515            font_size: settings.buffer_font_size(cx).into(),
23516            font_weight: settings.buffer_font.weight,
23517            line_height: relative(settings.buffer_line_height.value()),
23518            ..Default::default()
23519        };
23520        EditorElement::new(
23521            &self.prompt,
23522            EditorStyle {
23523                background: cx.theme().colors().editor_background,
23524                local_player: cx.theme().players().local(),
23525                text: text_style,
23526                ..Default::default()
23527            },
23528        )
23529    }
23530}
23531
23532impl Render for BreakpointPromptEditor {
23533    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23534        let editor_margins = *self.editor_margins.lock();
23535        let gutter_dimensions = editor_margins.gutter;
23536        h_flex()
23537            .key_context("Editor")
23538            .bg(cx.theme().colors().editor_background)
23539            .border_y_1()
23540            .border_color(cx.theme().status().info_border)
23541            .size_full()
23542            .py(window.line_height() / 2.5)
23543            .on_action(cx.listener(Self::confirm))
23544            .on_action(cx.listener(Self::cancel))
23545            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23546            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23547    }
23548}
23549
23550impl Focusable for BreakpointPromptEditor {
23551    fn focus_handle(&self, cx: &App) -> FocusHandle {
23552        self.prompt.focus_handle(cx)
23553    }
23554}
23555
23556fn all_edits_insertions_or_deletions(
23557    edits: &Vec<(Range<Anchor>, String)>,
23558    snapshot: &MultiBufferSnapshot,
23559) -> bool {
23560    let mut all_insertions = true;
23561    let mut all_deletions = true;
23562
23563    for (range, new_text) in edits.iter() {
23564        let range_is_empty = range.to_offset(&snapshot).is_empty();
23565        let text_is_empty = new_text.is_empty();
23566
23567        if range_is_empty != text_is_empty {
23568            if range_is_empty {
23569                all_deletions = false;
23570            } else {
23571                all_insertions = false;
23572            }
23573        } else {
23574            return false;
23575        }
23576
23577        if !all_insertions && !all_deletions {
23578            return false;
23579        }
23580    }
23581    all_insertions || all_deletions
23582}
23583
23584struct MissingEditPredictionKeybindingTooltip;
23585
23586impl Render for MissingEditPredictionKeybindingTooltip {
23587    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23588        ui::tooltip_container(window, cx, |container, _, cx| {
23589            container
23590                .flex_shrink_0()
23591                .max_w_80()
23592                .min_h(rems_from_px(124.))
23593                .justify_between()
23594                .child(
23595                    v_flex()
23596                        .flex_1()
23597                        .text_ui_sm(cx)
23598                        .child(Label::new("Conflict with Accept Keybinding"))
23599                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23600                )
23601                .child(
23602                    h_flex()
23603                        .pb_1()
23604                        .gap_1()
23605                        .items_end()
23606                        .w_full()
23607                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23608                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23609                        }))
23610                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23611                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23612                        })),
23613                )
23614        })
23615    }
23616}
23617
23618#[derive(Debug, Clone, Copy, PartialEq)]
23619pub struct LineHighlight {
23620    pub background: Background,
23621    pub border: Option<gpui::Hsla>,
23622    pub include_gutter: bool,
23623    pub type_id: Option<TypeId>,
23624}
23625
23626struct LineManipulationResult {
23627    pub new_text: String,
23628    pub line_count_before: usize,
23629    pub line_count_after: usize,
23630}
23631
23632fn render_diff_hunk_controls(
23633    row: u32,
23634    status: &DiffHunkStatus,
23635    hunk_range: Range<Anchor>,
23636    is_created_file: bool,
23637    line_height: Pixels,
23638    editor: &Entity<Editor>,
23639    _window: &mut Window,
23640    cx: &mut App,
23641) -> AnyElement {
23642    h_flex()
23643        .h(line_height)
23644        .mr_1()
23645        .gap_1()
23646        .px_0p5()
23647        .pb_1()
23648        .border_x_1()
23649        .border_b_1()
23650        .border_color(cx.theme().colors().border_variant)
23651        .rounded_b_lg()
23652        .bg(cx.theme().colors().editor_background)
23653        .gap_1()
23654        .block_mouse_except_scroll()
23655        .shadow_md()
23656        .child(if status.has_secondary_hunk() {
23657            Button::new(("stage", row as u64), "Stage")
23658                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23659                .tooltip({
23660                    let focus_handle = editor.focus_handle(cx);
23661                    move |window, cx| {
23662                        Tooltip::for_action_in(
23663                            "Stage Hunk",
23664                            &::git::ToggleStaged,
23665                            &focus_handle,
23666                            window,
23667                            cx,
23668                        )
23669                    }
23670                })
23671                .on_click({
23672                    let editor = editor.clone();
23673                    move |_event, _window, cx| {
23674                        editor.update(cx, |editor, cx| {
23675                            editor.stage_or_unstage_diff_hunks(
23676                                true,
23677                                vec![hunk_range.start..hunk_range.start],
23678                                cx,
23679                            );
23680                        });
23681                    }
23682                })
23683        } else {
23684            Button::new(("unstage", row as u64), "Unstage")
23685                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23686                .tooltip({
23687                    let focus_handle = editor.focus_handle(cx);
23688                    move |window, cx| {
23689                        Tooltip::for_action_in(
23690                            "Unstage Hunk",
23691                            &::git::ToggleStaged,
23692                            &focus_handle,
23693                            window,
23694                            cx,
23695                        )
23696                    }
23697                })
23698                .on_click({
23699                    let editor = editor.clone();
23700                    move |_event, _window, cx| {
23701                        editor.update(cx, |editor, cx| {
23702                            editor.stage_or_unstage_diff_hunks(
23703                                false,
23704                                vec![hunk_range.start..hunk_range.start],
23705                                cx,
23706                            );
23707                        });
23708                    }
23709                })
23710        })
23711        .child(
23712            Button::new(("restore", row as u64), "Restore")
23713                .tooltip({
23714                    let focus_handle = editor.focus_handle(cx);
23715                    move |window, cx| {
23716                        Tooltip::for_action_in(
23717                            "Restore Hunk",
23718                            &::git::Restore,
23719                            &focus_handle,
23720                            window,
23721                            cx,
23722                        )
23723                    }
23724                })
23725                .on_click({
23726                    let editor = editor.clone();
23727                    move |_event, window, cx| {
23728                        editor.update(cx, |editor, cx| {
23729                            let snapshot = editor.snapshot(window, cx);
23730                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23731                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23732                        });
23733                    }
23734                })
23735                .disabled(is_created_file),
23736        )
23737        .when(
23738            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23739            |el| {
23740                el.child(
23741                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23742                        .shape(IconButtonShape::Square)
23743                        .icon_size(IconSize::Small)
23744                        // .disabled(!has_multiple_hunks)
23745                        .tooltip({
23746                            let focus_handle = editor.focus_handle(cx);
23747                            move |window, cx| {
23748                                Tooltip::for_action_in(
23749                                    "Next Hunk",
23750                                    &GoToHunk,
23751                                    &focus_handle,
23752                                    window,
23753                                    cx,
23754                                )
23755                            }
23756                        })
23757                        .on_click({
23758                            let editor = editor.clone();
23759                            move |_event, window, cx| {
23760                                editor.update(cx, |editor, cx| {
23761                                    let snapshot = editor.snapshot(window, cx);
23762                                    let position =
23763                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23764                                    editor.go_to_hunk_before_or_after_position(
23765                                        &snapshot,
23766                                        position,
23767                                        Direction::Next,
23768                                        window,
23769                                        cx,
23770                                    );
23771                                    editor.expand_selected_diff_hunks(cx);
23772                                });
23773                            }
23774                        }),
23775                )
23776                .child(
23777                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23778                        .shape(IconButtonShape::Square)
23779                        .icon_size(IconSize::Small)
23780                        // .disabled(!has_multiple_hunks)
23781                        .tooltip({
23782                            let focus_handle = editor.focus_handle(cx);
23783                            move |window, cx| {
23784                                Tooltip::for_action_in(
23785                                    "Previous Hunk",
23786                                    &GoToPreviousHunk,
23787                                    &focus_handle,
23788                                    window,
23789                                    cx,
23790                                )
23791                            }
23792                        })
23793                        .on_click({
23794                            let editor = editor.clone();
23795                            move |_event, window, cx| {
23796                                editor.update(cx, |editor, cx| {
23797                                    let snapshot = editor.snapshot(window, cx);
23798                                    let point =
23799                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23800                                    editor.go_to_hunk_before_or_after_position(
23801                                        &snapshot,
23802                                        point,
23803                                        Direction::Prev,
23804                                        window,
23805                                        cx,
23806                                    );
23807                                    editor.expand_selected_diff_hunks(cx);
23808                                });
23809                            }
23810                        }),
23811                )
23812            },
23813        )
23814        .into_any_element()
23815}