editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_colors;
   33mod lsp_ext;
   34mod mouse_context_menu;
   35pub mod movement;
   36mod persistence;
   37mod proposed_changes_editor;
   38mod rust_analyzer_ext;
   39pub mod scroll;
   40mod selections_collection;
   41pub mod tasks;
   42
   43#[cfg(test)]
   44mod code_completion_tests;
   45#[cfg(test)]
   46mod edit_prediction_tests;
   47#[cfg(test)]
   48mod editor_tests;
   49mod signature_help;
   50#[cfg(any(test, feature = "test-support"))]
   51pub mod test;
   52
   53pub(crate) use actions::*;
   54pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   55pub use edit_prediction::Direction;
   56pub use editor_settings::{
   57    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   58    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap, ShowScrollbar,
   59};
   60pub use editor_settings_controls::*;
   61pub use element::{
   62    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   63};
   64pub use git::blame::BlameRenderer;
   65pub use hover_popover::hover_markdown_style;
   66pub use items::MAX_TAB_TITLE_LEN;
   67pub use lsp::CompletionContext;
   68pub use lsp_ext::lsp_tasks;
   69pub use multi_buffer::{
   70    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   71    RowInfo, ToOffset, ToPoint,
   72};
   73pub use proposed_changes_editor::{
   74    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
   75};
   76pub use text::Bias;
   77
   78use ::git::{
   79    Restore,
   80    blame::{BlameEntry, ParsedCommitMessage},
   81};
   82use aho_corasick::AhoCorasick;
   83use anyhow::{Context as _, Result, anyhow};
   84use blink_manager::BlinkManager;
   85use buffer_diff::DiffHunkStatus;
   86use client::{Collaborator, ParticipantIndex};
   87use clock::{AGENT_REPLICA_ID, ReplicaId};
   88use code_context_menus::{
   89    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   90    CompletionsMenu, ContextMenuOrigin,
   91};
   92use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   93use convert_case::{Case, Casing};
   94use dap::TelemetrySpawnLocation;
   95use display_map::*;
   96use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   97use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   98use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   99use futures::{
  100    FutureExt, StreamExt as _,
  101    future::{self, Shared, join},
  102    stream::FuturesUnordered,
  103};
  104use fuzzy::{StringMatch, StringMatchCandidate};
  105use git::blame::{GitBlame, GlobalBlameRenderer};
  106use gpui::{
  107    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  108    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  109    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  110    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  111    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  112    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  113    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  114    div, point, prelude::*, pulsating_between, px, relative, size,
  115};
  116use highlight_matching_bracket::refresh_matching_bracket_highlights;
  117use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  118use hover_popover::{HoverState, hide_hover};
  119use indent_guides::ActiveIndentGuidesState;
  120use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  121use itertools::Itertools;
  122use language::{
  123    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  124    BufferSnapshot, Capability, CharClassifier, CharKind, CodeLabel, CursorShape, DiagnosticEntry,
  125    DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind, IndentSize,
  126    Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal, TextObject,
  127    TransactionId, TreeSitterOptions, WordsQuery,
  128    language_settings::{
  129        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  130        all_language_settings, language_settings,
  131    },
  132    point_from_lsp, point_to_lsp, text_diff_with_options,
  133};
  134use linked_editing_ranges::refresh_linked_ranges;
  135use lsp::{
  136    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  137    LanguageServerId,
  138};
  139use lsp_colors::LspColorData;
  140use markdown::Markdown;
  141use mouse_context_menu::MouseContextMenu;
  142use movement::TextLayoutDetails;
  143use multi_buffer::{
  144    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  145    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  146};
  147use parking_lot::Mutex;
  148use persistence::DB;
  149use project::{
  150    BreakpointWithPosition, CodeAction, Completion, CompletionIntent, CompletionResponse,
  151    CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, Location, LocationLink,
  152    PrepareRenameResponse, Project, ProjectItem, ProjectPath, ProjectTransaction, TaskSourceKind,
  153    debugger::breakpoint_store::Breakpoint,
  154    debugger::{
  155        breakpoint_store::{
  156            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  157            BreakpointStoreEvent,
  158        },
  159        session::{Session, SessionEvent},
  160    },
  161    git_store::{GitStoreEvent, RepositoryEvent},
  162    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  163    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter},
  164    project_settings::{GitGutterSetting, ProjectSettings},
  165};
  166use rand::{seq::SliceRandom, thread_rng};
  167use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  168use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  169use selections_collection::{
  170    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  171};
  172use serde::{Deserialize, Serialize};
  173use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  174use smallvec::{SmallVec, smallvec};
  175use snippet::Snippet;
  176use std::{
  177    any::TypeId,
  178    borrow::Cow,
  179    cell::OnceCell,
  180    cell::RefCell,
  181    cmp::{self, Ordering, Reverse},
  182    iter::Peekable,
  183    mem,
  184    num::NonZeroU32,
  185    ops::Not,
  186    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  187    path::{Path, PathBuf},
  188    rc::Rc,
  189    sync::Arc,
  190    time::{Duration, Instant},
  191};
  192use sum_tree::TreeMap;
  193use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  194use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  195use theme::{
  196    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  197    observe_buffer_font_size_adjustment,
  198};
  199use ui::{
  200    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  201    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  202};
  203use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  204use workspace::{
  205    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  206    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  207    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  208    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  209    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  210    searchable::SearchEvent,
  211};
  212
  213use crate::{
  214    code_context_menus::CompletionsMenuSource,
  215    editor_settings::MultiCursorModifier,
  216    hover_links::{find_url, find_url_from_range},
  217    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  218};
  219
  220pub const FILE_HEADER_HEIGHT: u32 = 2;
  221pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  222pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  223const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  224const MAX_LINE_LEN: usize = 1024;
  225const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  226const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  227pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  228#[doc(hidden)]
  229pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  230const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  231
  232pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  233pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  234pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  235
  236pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  237pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  238pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  239
  240pub type RenderDiffHunkControlsFn = Arc<
  241    dyn Fn(
  242        u32,
  243        &DiffHunkStatus,
  244        Range<Anchor>,
  245        bool,
  246        Pixels,
  247        &Entity<Editor>,
  248        &mut Window,
  249        &mut App,
  250    ) -> AnyElement,
  251>;
  252
  253struct InlineValueCache {
  254    enabled: bool,
  255    inlays: Vec<InlayId>,
  256    refresh_task: Task<Option<()>>,
  257}
  258
  259impl InlineValueCache {
  260    fn new(enabled: bool) -> Self {
  261        Self {
  262            enabled,
  263            inlays: Vec::new(),
  264            refresh_task: Task::ready(None),
  265        }
  266    }
  267}
  268
  269#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  270pub enum InlayId {
  271    EditPrediction(usize),
  272    DebuggerValue(usize),
  273    // LSP
  274    Hint(usize),
  275    Color(usize),
  276}
  277
  278impl InlayId {
  279    fn id(&self) -> usize {
  280        match self {
  281            Self::EditPrediction(id) => *id,
  282            Self::DebuggerValue(id) => *id,
  283            Self::Hint(id) => *id,
  284            Self::Color(id) => *id,
  285        }
  286    }
  287}
  288
  289pub enum ActiveDebugLine {}
  290pub enum DebugStackFrameLine {}
  291enum DocumentHighlightRead {}
  292enum DocumentHighlightWrite {}
  293enum InputComposition {}
  294pub enum PendingInput {}
  295enum SelectedTextHighlight {}
  296
  297pub enum ConflictsOuter {}
  298pub enum ConflictsOurs {}
  299pub enum ConflictsTheirs {}
  300pub enum ConflictsOursMarker {}
  301pub enum ConflictsTheirsMarker {}
  302
  303#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  304pub enum Navigated {
  305    Yes,
  306    No,
  307}
  308
  309impl Navigated {
  310    pub fn from_bool(yes: bool) -> Navigated {
  311        if yes { Navigated::Yes } else { Navigated::No }
  312    }
  313}
  314
  315#[derive(Debug, Clone, PartialEq, Eq)]
  316enum DisplayDiffHunk {
  317    Folded {
  318        display_row: DisplayRow,
  319    },
  320    Unfolded {
  321        is_created_file: bool,
  322        diff_base_byte_range: Range<usize>,
  323        display_row_range: Range<DisplayRow>,
  324        multi_buffer_range: Range<Anchor>,
  325        status: DiffHunkStatus,
  326    },
  327}
  328
  329pub enum HideMouseCursorOrigin {
  330    TypingAction,
  331    MovementAction,
  332}
  333
  334pub fn init_settings(cx: &mut App) {
  335    EditorSettings::register(cx);
  336}
  337
  338pub fn init(cx: &mut App) {
  339    init_settings(cx);
  340
  341    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  342
  343    workspace::register_project_item::<Editor>(cx);
  344    workspace::FollowableViewRegistry::register::<Editor>(cx);
  345    workspace::register_serializable_item::<Editor>(cx);
  346
  347    cx.observe_new(
  348        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  349            workspace.register_action(Editor::new_file);
  350            workspace.register_action(Editor::new_file_vertical);
  351            workspace.register_action(Editor::new_file_horizontal);
  352            workspace.register_action(Editor::cancel_language_server_work);
  353            workspace.register_action(Editor::toggle_focus);
  354        },
  355    )
  356    .detach();
  357
  358    cx.on_action(move |_: &workspace::NewFile, cx| {
  359        let app_state = workspace::AppState::global(cx);
  360        if let Some(app_state) = app_state.upgrade() {
  361            workspace::open_new(
  362                Default::default(),
  363                app_state,
  364                cx,
  365                |workspace, window, cx| {
  366                    Editor::new_file(workspace, &Default::default(), window, cx)
  367                },
  368            )
  369            .detach();
  370        }
  371    });
  372    cx.on_action(move |_: &workspace::NewWindow, cx| {
  373        let app_state = workspace::AppState::global(cx);
  374        if let Some(app_state) = app_state.upgrade() {
  375            workspace::open_new(
  376                Default::default(),
  377                app_state,
  378                cx,
  379                |workspace, window, cx| {
  380                    cx.activate(true);
  381                    Editor::new_file(workspace, &Default::default(), window, cx)
  382                },
  383            )
  384            .detach();
  385        }
  386    });
  387}
  388
  389pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  390    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  391}
  392
  393pub trait DiagnosticRenderer {
  394    fn render_group(
  395        &self,
  396        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  397        buffer_id: BufferId,
  398        snapshot: EditorSnapshot,
  399        editor: WeakEntity<Editor>,
  400        cx: &mut App,
  401    ) -> Vec<BlockProperties<Anchor>>;
  402
  403    fn render_hover(
  404        &self,
  405        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  406        range: Range<Point>,
  407        buffer_id: BufferId,
  408        cx: &mut App,
  409    ) -> Option<Entity<markdown::Markdown>>;
  410
  411    fn open_link(
  412        &self,
  413        editor: &mut Editor,
  414        link: SharedString,
  415        window: &mut Window,
  416        cx: &mut Context<Editor>,
  417    );
  418}
  419
  420pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  421
  422impl GlobalDiagnosticRenderer {
  423    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  424        cx.try_global::<Self>().map(|g| g.0.clone())
  425    }
  426}
  427
  428impl gpui::Global for GlobalDiagnosticRenderer {}
  429pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  430    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  431}
  432
  433pub struct SearchWithinRange;
  434
  435trait InvalidationRegion {
  436    fn ranges(&self) -> &[Range<Anchor>];
  437}
  438
  439#[derive(Clone, Debug, PartialEq)]
  440pub enum SelectPhase {
  441    Begin {
  442        position: DisplayPoint,
  443        add: bool,
  444        click_count: usize,
  445    },
  446    BeginColumnar {
  447        position: DisplayPoint,
  448        reset: bool,
  449        mode: ColumnarMode,
  450        goal_column: u32,
  451    },
  452    Extend {
  453        position: DisplayPoint,
  454        click_count: usize,
  455    },
  456    Update {
  457        position: DisplayPoint,
  458        goal_column: u32,
  459        scroll_delta: gpui::Point<f32>,
  460    },
  461    End,
  462}
  463
  464#[derive(Clone, Debug, PartialEq)]
  465pub enum ColumnarMode {
  466    FromMouse,
  467    FromSelection,
  468}
  469
  470#[derive(Clone, Debug)]
  471pub enum SelectMode {
  472    Character,
  473    Word(Range<Anchor>),
  474    Line(Range<Anchor>),
  475    All,
  476}
  477
  478#[derive(Clone, PartialEq, Eq, Debug)]
  479pub enum EditorMode {
  480    SingleLine,
  481    AutoHeight {
  482        min_lines: usize,
  483        max_lines: Option<usize>,
  484    },
  485    Full {
  486        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  487        scale_ui_elements_with_buffer_font_size: bool,
  488        /// When set to `true`, the editor will render a background for the active line.
  489        show_active_line_background: bool,
  490        /// When set to `true`, the editor's height will be determined by its content.
  491        sized_by_content: bool,
  492    },
  493    Minimap {
  494        parent: WeakEntity<Editor>,
  495    },
  496}
  497
  498impl EditorMode {
  499    pub fn full() -> Self {
  500        Self::Full {
  501            scale_ui_elements_with_buffer_font_size: true,
  502            show_active_line_background: true,
  503            sized_by_content: false,
  504        }
  505    }
  506
  507    #[inline]
  508    pub fn is_full(&self) -> bool {
  509        matches!(self, Self::Full { .. })
  510    }
  511
  512    #[inline]
  513    pub fn is_single_line(&self) -> bool {
  514        matches!(self, Self::SingleLine { .. })
  515    }
  516
  517    #[inline]
  518    fn is_minimap(&self) -> bool {
  519        matches!(self, Self::Minimap { .. })
  520    }
  521}
  522
  523#[derive(Copy, Clone, Debug)]
  524pub enum SoftWrap {
  525    /// Prefer not to wrap at all.
  526    ///
  527    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  528    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  529    GitDiff,
  530    /// Prefer a single line generally, unless an overly long line is encountered.
  531    None,
  532    /// Soft wrap lines that exceed the editor width.
  533    EditorWidth,
  534    /// Soft wrap lines at the preferred line length.
  535    Column(u32),
  536    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  537    Bounded(u32),
  538}
  539
  540#[derive(Clone)]
  541pub struct EditorStyle {
  542    pub background: Hsla,
  543    pub border: Hsla,
  544    pub local_player: PlayerColor,
  545    pub text: TextStyle,
  546    pub scrollbar_width: Pixels,
  547    pub syntax: Arc<SyntaxTheme>,
  548    pub status: StatusColors,
  549    pub inlay_hints_style: HighlightStyle,
  550    pub edit_prediction_styles: EditPredictionStyles,
  551    pub unnecessary_code_fade: f32,
  552    pub show_underlines: bool,
  553}
  554
  555impl Default for EditorStyle {
  556    fn default() -> Self {
  557        Self {
  558            background: Hsla::default(),
  559            border: Hsla::default(),
  560            local_player: PlayerColor::default(),
  561            text: TextStyle::default(),
  562            scrollbar_width: Pixels::default(),
  563            syntax: Default::default(),
  564            // HACK: Status colors don't have a real default.
  565            // We should look into removing the status colors from the editor
  566            // style and retrieve them directly from the theme.
  567            status: StatusColors::dark(),
  568            inlay_hints_style: HighlightStyle::default(),
  569            edit_prediction_styles: EditPredictionStyles {
  570                insertion: HighlightStyle::default(),
  571                whitespace: HighlightStyle::default(),
  572            },
  573            unnecessary_code_fade: Default::default(),
  574            show_underlines: true,
  575        }
  576    }
  577}
  578
  579pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  580    let show_background = language_settings::language_settings(None, None, cx)
  581        .inlay_hints
  582        .show_background;
  583
  584    HighlightStyle {
  585        color: Some(cx.theme().status().hint),
  586        background_color: show_background.then(|| cx.theme().status().hint_background),
  587        ..HighlightStyle::default()
  588    }
  589}
  590
  591pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  592    EditPredictionStyles {
  593        insertion: HighlightStyle {
  594            color: Some(cx.theme().status().predictive),
  595            ..HighlightStyle::default()
  596        },
  597        whitespace: HighlightStyle {
  598            background_color: Some(cx.theme().status().created_background),
  599            ..HighlightStyle::default()
  600        },
  601    }
  602}
  603
  604type CompletionId = usize;
  605
  606pub(crate) enum EditDisplayMode {
  607    TabAccept,
  608    DiffPopover,
  609    Inline,
  610}
  611
  612enum EditPrediction {
  613    Edit {
  614        edits: Vec<(Range<Anchor>, String)>,
  615        edit_preview: Option<EditPreview>,
  616        display_mode: EditDisplayMode,
  617        snapshot: BufferSnapshot,
  618    },
  619    Move {
  620        target: Anchor,
  621        snapshot: BufferSnapshot,
  622    },
  623}
  624
  625struct EditPredictionState {
  626    inlay_ids: Vec<InlayId>,
  627    completion: EditPrediction,
  628    completion_id: Option<SharedString>,
  629    invalidation_range: Range<Anchor>,
  630}
  631
  632enum EditPredictionSettings {
  633    Disabled,
  634    Enabled {
  635        show_in_menu: bool,
  636        preview_requires_modifier: bool,
  637    },
  638}
  639
  640enum EditPredictionHighlight {}
  641
  642#[derive(Debug, Clone)]
  643struct InlineDiagnostic {
  644    message: SharedString,
  645    group_id: usize,
  646    is_primary: bool,
  647    start: Point,
  648    severity: lsp::DiagnosticSeverity,
  649}
  650
  651pub enum MenuEditPredictionsPolicy {
  652    Never,
  653    ByProvider,
  654}
  655
  656pub enum EditPredictionPreview {
  657    /// Modifier is not pressed
  658    Inactive { released_too_fast: bool },
  659    /// Modifier pressed
  660    Active {
  661        since: Instant,
  662        previous_scroll_position: Option<ScrollAnchor>,
  663    },
  664}
  665
  666impl EditPredictionPreview {
  667    pub fn released_too_fast(&self) -> bool {
  668        match self {
  669            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  670            EditPredictionPreview::Active { .. } => false,
  671        }
  672    }
  673
  674    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  675        if let EditPredictionPreview::Active {
  676            previous_scroll_position,
  677            ..
  678        } = self
  679        {
  680            *previous_scroll_position = scroll_position;
  681        }
  682    }
  683}
  684
  685pub struct ContextMenuOptions {
  686    pub min_entries_visible: usize,
  687    pub max_entries_visible: usize,
  688    pub placement: Option<ContextMenuPlacement>,
  689}
  690
  691#[derive(Debug, Clone, PartialEq, Eq)]
  692pub enum ContextMenuPlacement {
  693    Above,
  694    Below,
  695}
  696
  697#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  698struct EditorActionId(usize);
  699
  700impl EditorActionId {
  701    pub fn post_inc(&mut self) -> Self {
  702        let answer = self.0;
  703
  704        *self = Self(answer + 1);
  705
  706        Self(answer)
  707    }
  708}
  709
  710// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  711// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  712
  713type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  714type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  715
  716#[derive(Default)]
  717struct ScrollbarMarkerState {
  718    scrollbar_size: Size<Pixels>,
  719    dirty: bool,
  720    markers: Arc<[PaintQuad]>,
  721    pending_refresh: Option<Task<Result<()>>>,
  722}
  723
  724impl ScrollbarMarkerState {
  725    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  726        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  727    }
  728}
  729
  730#[derive(Clone, Copy, PartialEq, Eq)]
  731pub enum MinimapVisibility {
  732    Disabled,
  733    Enabled {
  734        /// The configuration currently present in the users settings.
  735        setting_configuration: bool,
  736        /// Whether to override the currently set visibility from the users setting.
  737        toggle_override: bool,
  738    },
  739}
  740
  741impl MinimapVisibility {
  742    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  743        if mode.is_full() {
  744            Self::Enabled {
  745                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  746                toggle_override: false,
  747            }
  748        } else {
  749            Self::Disabled
  750        }
  751    }
  752
  753    fn hidden(&self) -> Self {
  754        match *self {
  755            Self::Enabled {
  756                setting_configuration,
  757                ..
  758            } => Self::Enabled {
  759                setting_configuration,
  760                toggle_override: setting_configuration,
  761            },
  762            Self::Disabled => Self::Disabled,
  763        }
  764    }
  765
  766    fn disabled(&self) -> bool {
  767        match *self {
  768            Self::Disabled => true,
  769            _ => false,
  770        }
  771    }
  772
  773    fn settings_visibility(&self) -> bool {
  774        match *self {
  775            Self::Enabled {
  776                setting_configuration,
  777                ..
  778            } => setting_configuration,
  779            _ => false,
  780        }
  781    }
  782
  783    fn visible(&self) -> bool {
  784        match *self {
  785            Self::Enabled {
  786                setting_configuration,
  787                toggle_override,
  788            } => setting_configuration ^ toggle_override,
  789            _ => false,
  790        }
  791    }
  792
  793    fn toggle_visibility(&self) -> Self {
  794        match *self {
  795            Self::Enabled {
  796                toggle_override,
  797                setting_configuration,
  798            } => Self::Enabled {
  799                setting_configuration,
  800                toggle_override: !toggle_override,
  801            },
  802            Self::Disabled => Self::Disabled,
  803        }
  804    }
  805}
  806
  807#[derive(Clone, Debug)]
  808struct RunnableTasks {
  809    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  810    offset: multi_buffer::Anchor,
  811    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  812    column: u32,
  813    // Values of all named captures, including those starting with '_'
  814    extra_variables: HashMap<String, String>,
  815    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  816    context_range: Range<BufferOffset>,
  817}
  818
  819impl RunnableTasks {
  820    fn resolve<'a>(
  821        &'a self,
  822        cx: &'a task::TaskContext,
  823    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  824        self.templates.iter().filter_map(|(kind, template)| {
  825            template
  826                .resolve_task(&kind.to_id_base(), cx)
  827                .map(|task| (kind.clone(), task))
  828        })
  829    }
  830}
  831
  832#[derive(Clone)]
  833pub struct ResolvedTasks {
  834    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  835    position: Anchor,
  836}
  837
  838#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  839struct BufferOffset(usize);
  840
  841// Addons allow storing per-editor state in other crates (e.g. Vim)
  842pub trait Addon: 'static {
  843    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  844
  845    fn render_buffer_header_controls(
  846        &self,
  847        _: &ExcerptInfo,
  848        _: &Window,
  849        _: &App,
  850    ) -> Option<AnyElement> {
  851        None
  852    }
  853
  854    fn to_any(&self) -> &dyn std::any::Any;
  855
  856    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  857        None
  858    }
  859}
  860
  861struct ChangeLocation {
  862    current: Option<Vec<Anchor>>,
  863    original: Vec<Anchor>,
  864}
  865impl ChangeLocation {
  866    fn locations(&self) -> &[Anchor] {
  867        self.current.as_ref().unwrap_or(&self.original)
  868    }
  869}
  870
  871/// A set of caret positions, registered when the editor was edited.
  872pub struct ChangeList {
  873    changes: Vec<ChangeLocation>,
  874    /// Currently "selected" change.
  875    position: Option<usize>,
  876}
  877
  878impl ChangeList {
  879    pub fn new() -> Self {
  880        Self {
  881            changes: Vec::new(),
  882            position: None,
  883        }
  884    }
  885
  886    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  887    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  888    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  889        if self.changes.is_empty() {
  890            return None;
  891        }
  892
  893        let prev = self.position.unwrap_or(self.changes.len());
  894        let next = if direction == Direction::Prev {
  895            prev.saturating_sub(count)
  896        } else {
  897            (prev + count).min(self.changes.len() - 1)
  898        };
  899        self.position = Some(next);
  900        self.changes.get(next).map(|change| change.locations())
  901    }
  902
  903    /// Adds a new change to the list, resetting the change list position.
  904    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  905        self.position.take();
  906        if let Some(last) = self.changes.last_mut()
  907            && group
  908        {
  909            last.current = Some(new_positions)
  910        } else {
  911            self.changes.push(ChangeLocation {
  912                original: new_positions,
  913                current: None,
  914            });
  915        }
  916    }
  917
  918    pub fn last(&self) -> Option<&[Anchor]> {
  919        self.changes.last().map(|change| change.locations())
  920    }
  921
  922    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  923        self.changes.last().map(|change| change.original.as_slice())
  924    }
  925
  926    pub fn invert_last_group(&mut self) {
  927        if let Some(last) = self.changes.last_mut() {
  928            if let Some(current) = last.current.as_mut() {
  929                mem::swap(&mut last.original, current);
  930            }
  931        }
  932    }
  933}
  934
  935#[derive(Clone)]
  936struct InlineBlamePopoverState {
  937    scroll_handle: ScrollHandle,
  938    commit_message: Option<ParsedCommitMessage>,
  939    markdown: Entity<Markdown>,
  940}
  941
  942struct InlineBlamePopover {
  943    position: gpui::Point<Pixels>,
  944    hide_task: Option<Task<()>>,
  945    popover_bounds: Option<Bounds<Pixels>>,
  946    popover_state: InlineBlamePopoverState,
  947    keyboard_grace: bool,
  948}
  949
  950enum SelectionDragState {
  951    /// State when no drag related activity is detected.
  952    None,
  953    /// State when the mouse is down on a selection that is about to be dragged.
  954    ReadyToDrag {
  955        selection: Selection<Anchor>,
  956        click_position: gpui::Point<Pixels>,
  957        mouse_down_time: Instant,
  958    },
  959    /// State when the mouse is dragging the selection in the editor.
  960    Dragging {
  961        selection: Selection<Anchor>,
  962        drop_cursor: Selection<Anchor>,
  963        hide_drop_cursor: bool,
  964    },
  965}
  966
  967enum ColumnarSelectionState {
  968    FromMouse {
  969        selection_tail: Anchor,
  970        display_point: Option<DisplayPoint>,
  971    },
  972    FromSelection {
  973        selection_tail: Anchor,
  974    },
  975}
  976
  977/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  978/// a breakpoint on them.
  979#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  980struct PhantomBreakpointIndicator {
  981    display_row: DisplayRow,
  982    /// There's a small debounce between hovering over the line and showing the indicator.
  983    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  984    is_active: bool,
  985    collides_with_existing_breakpoint: bool,
  986}
  987
  988/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  989///
  990/// See the [module level documentation](self) for more information.
  991pub struct Editor {
  992    focus_handle: FocusHandle,
  993    last_focused_descendant: Option<WeakFocusHandle>,
  994    /// The text buffer being edited
  995    buffer: Entity<MultiBuffer>,
  996    /// Map of how text in the buffer should be displayed.
  997    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  998    pub display_map: Entity<DisplayMap>,
  999    pub selections: SelectionsCollection,
 1000    pub scroll_manager: ScrollManager,
 1001    /// When inline assist editors are linked, they all render cursors because
 1002    /// typing enters text into each of them, even the ones that aren't focused.
 1003    pub(crate) show_cursor_when_unfocused: bool,
 1004    columnar_selection_state: Option<ColumnarSelectionState>,
 1005    add_selections_state: Option<AddSelectionsState>,
 1006    select_next_state: Option<SelectNextState>,
 1007    select_prev_state: Option<SelectNextState>,
 1008    selection_history: SelectionHistory,
 1009    defer_selection_effects: bool,
 1010    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1011    autoclose_regions: Vec<AutocloseRegion>,
 1012    snippet_stack: InvalidationStack<SnippetState>,
 1013    select_syntax_node_history: SelectSyntaxNodeHistory,
 1014    ime_transaction: Option<TransactionId>,
 1015    pub diagnostics_max_severity: DiagnosticSeverity,
 1016    active_diagnostics: ActiveDiagnostic,
 1017    show_inline_diagnostics: bool,
 1018    inline_diagnostics_update: Task<()>,
 1019    inline_diagnostics_enabled: bool,
 1020    diagnostics_enabled: bool,
 1021    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1022    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1023    hard_wrap: Option<usize>,
 1024
 1025    // TODO: make this a access method
 1026    pub project: Option<Entity<Project>>,
 1027    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1028    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1029    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1030    blink_manager: Entity<BlinkManager>,
 1031    show_cursor_names: bool,
 1032    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1033    pub show_local_selections: bool,
 1034    mode: EditorMode,
 1035    show_breadcrumbs: bool,
 1036    show_gutter: bool,
 1037    show_scrollbars: ScrollbarAxes,
 1038    minimap_visibility: MinimapVisibility,
 1039    offset_content: bool,
 1040    disable_expand_excerpt_buttons: bool,
 1041    show_line_numbers: Option<bool>,
 1042    use_relative_line_numbers: Option<bool>,
 1043    show_git_diff_gutter: Option<bool>,
 1044    show_code_actions: Option<bool>,
 1045    show_runnables: Option<bool>,
 1046    show_breakpoints: Option<bool>,
 1047    show_wrap_guides: Option<bool>,
 1048    show_indent_guides: Option<bool>,
 1049    placeholder_text: Option<Arc<str>>,
 1050    highlight_order: usize,
 1051    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1052    background_highlights: TreeMap<HighlightKey, BackgroundHighlight>,
 1053    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1054    scrollbar_marker_state: ScrollbarMarkerState,
 1055    active_indent_guides_state: ActiveIndentGuidesState,
 1056    nav_history: Option<ItemNavHistory>,
 1057    context_menu: RefCell<Option<CodeContextMenu>>,
 1058    context_menu_options: Option<ContextMenuOptions>,
 1059    mouse_context_menu: Option<MouseContextMenu>,
 1060    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1061    inline_blame_popover: Option<InlineBlamePopover>,
 1062    inline_blame_popover_show_task: Option<Task<()>>,
 1063    signature_help_state: SignatureHelpState,
 1064    auto_signature_help: Option<bool>,
 1065    find_all_references_task_sources: Vec<Anchor>,
 1066    next_completion_id: CompletionId,
 1067    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1068    code_actions_task: Option<Task<Result<()>>>,
 1069    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1070    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1071    document_highlights_task: Option<Task<()>>,
 1072    linked_editing_range_task: Option<Task<Option<()>>>,
 1073    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1074    pending_rename: Option<RenameState>,
 1075    searchable: bool,
 1076    cursor_shape: CursorShape,
 1077    current_line_highlight: Option<CurrentLineHighlight>,
 1078    collapse_matches: bool,
 1079    autoindent_mode: Option<AutoindentMode>,
 1080    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1081    input_enabled: bool,
 1082    use_modal_editing: bool,
 1083    read_only: bool,
 1084    leader_id: Option<CollaboratorId>,
 1085    remote_id: Option<ViewId>,
 1086    pub hover_state: HoverState,
 1087    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1088    gutter_hovered: bool,
 1089    hovered_link_state: Option<HoveredLinkState>,
 1090    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1091    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1092    active_edit_prediction: Option<EditPredictionState>,
 1093    /// Used to prevent flickering as the user types while the menu is open
 1094    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1095    edit_prediction_settings: EditPredictionSettings,
 1096    edit_predictions_hidden_for_vim_mode: bool,
 1097    show_edit_predictions_override: Option<bool>,
 1098    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1099    edit_prediction_preview: EditPredictionPreview,
 1100    edit_prediction_indent_conflict: bool,
 1101    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1102    inlay_hint_cache: InlayHintCache,
 1103    next_inlay_id: usize,
 1104    _subscriptions: Vec<Subscription>,
 1105    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1106    gutter_dimensions: GutterDimensions,
 1107    style: Option<EditorStyle>,
 1108    text_style_refinement: Option<TextStyleRefinement>,
 1109    next_editor_action_id: EditorActionId,
 1110    editor_actions: Rc<
 1111        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1112    >,
 1113    use_autoclose: bool,
 1114    use_auto_surround: bool,
 1115    auto_replace_emoji_shortcode: bool,
 1116    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1117    show_git_blame_gutter: bool,
 1118    show_git_blame_inline: bool,
 1119    show_git_blame_inline_delay_task: Option<Task<()>>,
 1120    git_blame_inline_enabled: bool,
 1121    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1122    serialize_dirty_buffers: bool,
 1123    show_selection_menu: Option<bool>,
 1124    blame: Option<Entity<GitBlame>>,
 1125    blame_subscription: Option<Subscription>,
 1126    custom_context_menu: Option<
 1127        Box<
 1128            dyn 'static
 1129                + Fn(
 1130                    &mut Self,
 1131                    DisplayPoint,
 1132                    &mut Window,
 1133                    &mut Context<Self>,
 1134                ) -> Option<Entity<ui::ContextMenu>>,
 1135        >,
 1136    >,
 1137    last_bounds: Option<Bounds<Pixels>>,
 1138    last_position_map: Option<Rc<PositionMap>>,
 1139    expect_bounds_change: Option<Bounds<Pixels>>,
 1140    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1141    tasks_update_task: Option<Task<()>>,
 1142    breakpoint_store: Option<Entity<BreakpointStore>>,
 1143    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1144    hovered_diff_hunk_row: Option<DisplayRow>,
 1145    pull_diagnostics_task: Task<()>,
 1146    in_project_search: bool,
 1147    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1148    breadcrumb_header: Option<String>,
 1149    focused_block: Option<FocusedBlock>,
 1150    next_scroll_position: NextScrollCursorCenterTopBottom,
 1151    addons: HashMap<TypeId, Box<dyn Addon>>,
 1152    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1153    load_diff_task: Option<Shared<Task<()>>>,
 1154    /// Whether we are temporarily displaying a diff other than git's
 1155    temporary_diff_override: bool,
 1156    selection_mark_mode: bool,
 1157    toggle_fold_multiple_buffers: Task<()>,
 1158    _scroll_cursor_center_top_bottom_task: Task<()>,
 1159    serialize_selections: Task<()>,
 1160    serialize_folds: Task<()>,
 1161    mouse_cursor_hidden: bool,
 1162    minimap: Option<Entity<Self>>,
 1163    hide_mouse_mode: HideMouseMode,
 1164    pub change_list: ChangeList,
 1165    inline_value_cache: InlineValueCache,
 1166    selection_drag_state: SelectionDragState,
 1167    next_color_inlay_id: usize,
 1168    colors: Option<LspColorData>,
 1169    folding_newlines: Task<()>,
 1170}
 1171
 1172#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1173enum NextScrollCursorCenterTopBottom {
 1174    #[default]
 1175    Center,
 1176    Top,
 1177    Bottom,
 1178}
 1179
 1180impl NextScrollCursorCenterTopBottom {
 1181    fn next(&self) -> Self {
 1182        match self {
 1183            Self::Center => Self::Top,
 1184            Self::Top => Self::Bottom,
 1185            Self::Bottom => Self::Center,
 1186        }
 1187    }
 1188}
 1189
 1190#[derive(Clone)]
 1191pub struct EditorSnapshot {
 1192    pub mode: EditorMode,
 1193    show_gutter: bool,
 1194    show_line_numbers: Option<bool>,
 1195    show_git_diff_gutter: Option<bool>,
 1196    show_code_actions: Option<bool>,
 1197    show_runnables: Option<bool>,
 1198    show_breakpoints: Option<bool>,
 1199    git_blame_gutter_max_author_length: Option<usize>,
 1200    pub display_snapshot: DisplaySnapshot,
 1201    pub placeholder_text: Option<Arc<str>>,
 1202    is_focused: bool,
 1203    scroll_anchor: ScrollAnchor,
 1204    ongoing_scroll: OngoingScroll,
 1205    current_line_highlight: CurrentLineHighlight,
 1206    gutter_hovered: bool,
 1207}
 1208
 1209#[derive(Default, Debug, Clone, Copy)]
 1210pub struct GutterDimensions {
 1211    pub left_padding: Pixels,
 1212    pub right_padding: Pixels,
 1213    pub width: Pixels,
 1214    pub margin: Pixels,
 1215    pub git_blame_entries_width: Option<Pixels>,
 1216}
 1217
 1218impl GutterDimensions {
 1219    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1220        Self {
 1221            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1222            ..Default::default()
 1223        }
 1224    }
 1225
 1226    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1227        -cx.text_system().descent(font_id, font_size)
 1228    }
 1229    /// The full width of the space taken up by the gutter.
 1230    pub fn full_width(&self) -> Pixels {
 1231        self.margin + self.width
 1232    }
 1233
 1234    /// The width of the space reserved for the fold indicators,
 1235    /// use alongside 'justify_end' and `gutter_width` to
 1236    /// right align content with the line numbers
 1237    pub fn fold_area_width(&self) -> Pixels {
 1238        self.margin + self.right_padding
 1239    }
 1240}
 1241
 1242struct CharacterDimensions {
 1243    em_width: Pixels,
 1244    em_advance: Pixels,
 1245    line_height: Pixels,
 1246}
 1247
 1248#[derive(Debug)]
 1249pub struct RemoteSelection {
 1250    pub replica_id: ReplicaId,
 1251    pub selection: Selection<Anchor>,
 1252    pub cursor_shape: CursorShape,
 1253    pub collaborator_id: CollaboratorId,
 1254    pub line_mode: bool,
 1255    pub user_name: Option<SharedString>,
 1256    pub color: PlayerColor,
 1257}
 1258
 1259#[derive(Clone, Debug)]
 1260struct SelectionHistoryEntry {
 1261    selections: Arc<[Selection<Anchor>]>,
 1262    select_next_state: Option<SelectNextState>,
 1263    select_prev_state: Option<SelectNextState>,
 1264    add_selections_state: Option<AddSelectionsState>,
 1265}
 1266
 1267#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1268enum SelectionHistoryMode {
 1269    Normal,
 1270    Undoing,
 1271    Redoing,
 1272    Skipping,
 1273}
 1274
 1275#[derive(Clone, PartialEq, Eq, Hash)]
 1276struct HoveredCursor {
 1277    replica_id: u16,
 1278    selection_id: usize,
 1279}
 1280
 1281impl Default for SelectionHistoryMode {
 1282    fn default() -> Self {
 1283        Self::Normal
 1284    }
 1285}
 1286
 1287#[derive(Debug)]
 1288/// SelectionEffects controls the side-effects of updating the selection.
 1289///
 1290/// The default behaviour does "what you mostly want":
 1291/// - it pushes to the nav history if the cursor moved by >10 lines
 1292/// - it re-triggers completion requests
 1293/// - it scrolls to fit
 1294///
 1295/// You might want to modify these behaviours. For example when doing a "jump"
 1296/// like go to definition, we always want to add to nav history; but when scrolling
 1297/// in vim mode we never do.
 1298///
 1299/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1300/// move.
 1301#[derive(Clone)]
 1302pub struct SelectionEffects {
 1303    nav_history: Option<bool>,
 1304    completions: bool,
 1305    scroll: Option<Autoscroll>,
 1306}
 1307
 1308impl Default for SelectionEffects {
 1309    fn default() -> Self {
 1310        Self {
 1311            nav_history: None,
 1312            completions: true,
 1313            scroll: Some(Autoscroll::fit()),
 1314        }
 1315    }
 1316}
 1317impl SelectionEffects {
 1318    pub fn scroll(scroll: Autoscroll) -> Self {
 1319        Self {
 1320            scroll: Some(scroll),
 1321            ..Default::default()
 1322        }
 1323    }
 1324
 1325    pub fn no_scroll() -> Self {
 1326        Self {
 1327            scroll: None,
 1328            ..Default::default()
 1329        }
 1330    }
 1331
 1332    pub fn completions(self, completions: bool) -> Self {
 1333        Self {
 1334            completions,
 1335            ..self
 1336        }
 1337    }
 1338
 1339    pub fn nav_history(self, nav_history: bool) -> Self {
 1340        Self {
 1341            nav_history: Some(nav_history),
 1342            ..self
 1343        }
 1344    }
 1345}
 1346
 1347struct DeferredSelectionEffectsState {
 1348    changed: bool,
 1349    effects: SelectionEffects,
 1350    old_cursor_position: Anchor,
 1351    history_entry: SelectionHistoryEntry,
 1352}
 1353
 1354#[derive(Default)]
 1355struct SelectionHistory {
 1356    #[allow(clippy::type_complexity)]
 1357    selections_by_transaction:
 1358        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1359    mode: SelectionHistoryMode,
 1360    undo_stack: VecDeque<SelectionHistoryEntry>,
 1361    redo_stack: VecDeque<SelectionHistoryEntry>,
 1362}
 1363
 1364impl SelectionHistory {
 1365    #[track_caller]
 1366    fn insert_transaction(
 1367        &mut self,
 1368        transaction_id: TransactionId,
 1369        selections: Arc<[Selection<Anchor>]>,
 1370    ) {
 1371        if selections.is_empty() {
 1372            log::error!(
 1373                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1374                std::panic::Location::caller()
 1375            );
 1376            return;
 1377        }
 1378        self.selections_by_transaction
 1379            .insert(transaction_id, (selections, None));
 1380    }
 1381
 1382    #[allow(clippy::type_complexity)]
 1383    fn transaction(
 1384        &self,
 1385        transaction_id: TransactionId,
 1386    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1387        self.selections_by_transaction.get(&transaction_id)
 1388    }
 1389
 1390    #[allow(clippy::type_complexity)]
 1391    fn transaction_mut(
 1392        &mut self,
 1393        transaction_id: TransactionId,
 1394    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1395        self.selections_by_transaction.get_mut(&transaction_id)
 1396    }
 1397
 1398    fn push(&mut self, entry: SelectionHistoryEntry) {
 1399        if !entry.selections.is_empty() {
 1400            match self.mode {
 1401                SelectionHistoryMode::Normal => {
 1402                    self.push_undo(entry);
 1403                    self.redo_stack.clear();
 1404                }
 1405                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1406                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1407                SelectionHistoryMode::Skipping => {}
 1408            }
 1409        }
 1410    }
 1411
 1412    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1413        if self
 1414            .undo_stack
 1415            .back()
 1416            .map_or(true, |e| e.selections != entry.selections)
 1417        {
 1418            self.undo_stack.push_back(entry);
 1419            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1420                self.undo_stack.pop_front();
 1421            }
 1422        }
 1423    }
 1424
 1425    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1426        if self
 1427            .redo_stack
 1428            .back()
 1429            .map_or(true, |e| e.selections != entry.selections)
 1430        {
 1431            self.redo_stack.push_back(entry);
 1432            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1433                self.redo_stack.pop_front();
 1434            }
 1435        }
 1436    }
 1437}
 1438
 1439#[derive(Clone, Copy)]
 1440pub struct RowHighlightOptions {
 1441    pub autoscroll: bool,
 1442    pub include_gutter: bool,
 1443}
 1444
 1445impl Default for RowHighlightOptions {
 1446    fn default() -> Self {
 1447        Self {
 1448            autoscroll: Default::default(),
 1449            include_gutter: true,
 1450        }
 1451    }
 1452}
 1453
 1454struct RowHighlight {
 1455    index: usize,
 1456    range: Range<Anchor>,
 1457    color: Hsla,
 1458    options: RowHighlightOptions,
 1459    type_id: TypeId,
 1460}
 1461
 1462#[derive(Clone, Debug)]
 1463struct AddSelectionsState {
 1464    groups: Vec<AddSelectionsGroup>,
 1465}
 1466
 1467#[derive(Clone, Debug)]
 1468struct AddSelectionsGroup {
 1469    above: bool,
 1470    stack: Vec<usize>,
 1471}
 1472
 1473#[derive(Clone)]
 1474struct SelectNextState {
 1475    query: AhoCorasick,
 1476    wordwise: bool,
 1477    done: bool,
 1478}
 1479
 1480impl std::fmt::Debug for SelectNextState {
 1481    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1482        f.debug_struct(std::any::type_name::<Self>())
 1483            .field("wordwise", &self.wordwise)
 1484            .field("done", &self.done)
 1485            .finish()
 1486    }
 1487}
 1488
 1489#[derive(Debug)]
 1490struct AutocloseRegion {
 1491    selection_id: usize,
 1492    range: Range<Anchor>,
 1493    pair: BracketPair,
 1494}
 1495
 1496#[derive(Debug)]
 1497struct SnippetState {
 1498    ranges: Vec<Vec<Range<Anchor>>>,
 1499    active_index: usize,
 1500    choices: Vec<Option<Vec<String>>>,
 1501}
 1502
 1503#[doc(hidden)]
 1504pub struct RenameState {
 1505    pub range: Range<Anchor>,
 1506    pub old_name: Arc<str>,
 1507    pub editor: Entity<Editor>,
 1508    block_id: CustomBlockId,
 1509}
 1510
 1511struct InvalidationStack<T>(Vec<T>);
 1512
 1513struct RegisteredEditPredictionProvider {
 1514    provider: Arc<dyn EditPredictionProviderHandle>,
 1515    _subscription: Subscription,
 1516}
 1517
 1518#[derive(Debug, PartialEq, Eq)]
 1519pub struct ActiveDiagnosticGroup {
 1520    pub active_range: Range<Anchor>,
 1521    pub active_message: String,
 1522    pub group_id: usize,
 1523    pub blocks: HashSet<CustomBlockId>,
 1524}
 1525
 1526#[derive(Debug, PartialEq, Eq)]
 1527
 1528pub(crate) enum ActiveDiagnostic {
 1529    None,
 1530    All,
 1531    Group(ActiveDiagnosticGroup),
 1532}
 1533
 1534#[derive(Serialize, Deserialize, Clone, Debug)]
 1535pub struct ClipboardSelection {
 1536    /// The number of bytes in this selection.
 1537    pub len: usize,
 1538    /// Whether this was a full-line selection.
 1539    pub is_entire_line: bool,
 1540    /// The indentation of the first line when this content was originally copied.
 1541    pub first_line_indent: u32,
 1542}
 1543
 1544// selections, scroll behavior, was newest selection reversed
 1545type SelectSyntaxNodeHistoryState = (
 1546    Box<[Selection<usize>]>,
 1547    SelectSyntaxNodeScrollBehavior,
 1548    bool,
 1549);
 1550
 1551#[derive(Default)]
 1552struct SelectSyntaxNodeHistory {
 1553    stack: Vec<SelectSyntaxNodeHistoryState>,
 1554    // disable temporarily to allow changing selections without losing the stack
 1555    pub disable_clearing: bool,
 1556}
 1557
 1558impl SelectSyntaxNodeHistory {
 1559    pub fn try_clear(&mut self) {
 1560        if !self.disable_clearing {
 1561            self.stack.clear();
 1562        }
 1563    }
 1564
 1565    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1566        self.stack.push(selection);
 1567    }
 1568
 1569    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1570        self.stack.pop()
 1571    }
 1572}
 1573
 1574enum SelectSyntaxNodeScrollBehavior {
 1575    CursorTop,
 1576    FitSelection,
 1577    CursorBottom,
 1578}
 1579
 1580#[derive(Debug)]
 1581pub(crate) struct NavigationData {
 1582    cursor_anchor: Anchor,
 1583    cursor_position: Point,
 1584    scroll_anchor: ScrollAnchor,
 1585    scroll_top_row: u32,
 1586}
 1587
 1588#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1589pub enum GotoDefinitionKind {
 1590    Symbol,
 1591    Declaration,
 1592    Type,
 1593    Implementation,
 1594}
 1595
 1596#[derive(Debug, Clone)]
 1597enum InlayHintRefreshReason {
 1598    ModifiersChanged(bool),
 1599    Toggle(bool),
 1600    SettingsChange(InlayHintSettings),
 1601    NewLinesShown,
 1602    BufferEdited(HashSet<Arc<Language>>),
 1603    RefreshRequested,
 1604    ExcerptsRemoved(Vec<ExcerptId>),
 1605}
 1606
 1607impl InlayHintRefreshReason {
 1608    fn description(&self) -> &'static str {
 1609        match self {
 1610            Self::ModifiersChanged(_) => "modifiers changed",
 1611            Self::Toggle(_) => "toggle",
 1612            Self::SettingsChange(_) => "settings change",
 1613            Self::NewLinesShown => "new lines shown",
 1614            Self::BufferEdited(_) => "buffer edited",
 1615            Self::RefreshRequested => "refresh requested",
 1616            Self::ExcerptsRemoved(_) => "excerpts removed",
 1617        }
 1618    }
 1619}
 1620
 1621pub enum FormatTarget {
 1622    Buffers(HashSet<Entity<Buffer>>),
 1623    Ranges(Vec<Range<MultiBufferPoint>>),
 1624}
 1625
 1626pub(crate) struct FocusedBlock {
 1627    id: BlockId,
 1628    focus_handle: WeakFocusHandle,
 1629}
 1630
 1631#[derive(Clone)]
 1632enum JumpData {
 1633    MultiBufferRow {
 1634        row: MultiBufferRow,
 1635        line_offset_from_top: u32,
 1636    },
 1637    MultiBufferPoint {
 1638        excerpt_id: ExcerptId,
 1639        position: Point,
 1640        anchor: text::Anchor,
 1641        line_offset_from_top: u32,
 1642    },
 1643}
 1644
 1645pub enum MultibufferSelectionMode {
 1646    First,
 1647    All,
 1648}
 1649
 1650#[derive(Clone, Copy, Debug, Default)]
 1651pub struct RewrapOptions {
 1652    pub override_language_settings: bool,
 1653    pub preserve_existing_whitespace: bool,
 1654}
 1655
 1656impl Editor {
 1657    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1658        let buffer = cx.new(|cx| Buffer::local("", cx));
 1659        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1660        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1661    }
 1662
 1663    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1664        let buffer = cx.new(|cx| Buffer::local("", cx));
 1665        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1666        Self::new(EditorMode::full(), buffer, None, window, cx)
 1667    }
 1668
 1669    pub fn auto_height(
 1670        min_lines: usize,
 1671        max_lines: usize,
 1672        window: &mut Window,
 1673        cx: &mut Context<Self>,
 1674    ) -> Self {
 1675        let buffer = cx.new(|cx| Buffer::local("", cx));
 1676        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1677        Self::new(
 1678            EditorMode::AutoHeight {
 1679                min_lines,
 1680                max_lines: Some(max_lines),
 1681            },
 1682            buffer,
 1683            None,
 1684            window,
 1685            cx,
 1686        )
 1687    }
 1688
 1689    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1690    /// The editor grows as tall as needed to fit its content.
 1691    pub fn auto_height_unbounded(
 1692        min_lines: usize,
 1693        window: &mut Window,
 1694        cx: &mut Context<Self>,
 1695    ) -> Self {
 1696        let buffer = cx.new(|cx| Buffer::local("", cx));
 1697        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1698        Self::new(
 1699            EditorMode::AutoHeight {
 1700                min_lines,
 1701                max_lines: None,
 1702            },
 1703            buffer,
 1704            None,
 1705            window,
 1706            cx,
 1707        )
 1708    }
 1709
 1710    pub fn for_buffer(
 1711        buffer: Entity<Buffer>,
 1712        project: Option<Entity<Project>>,
 1713        window: &mut Window,
 1714        cx: &mut Context<Self>,
 1715    ) -> Self {
 1716        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1717        Self::new(EditorMode::full(), buffer, project, window, cx)
 1718    }
 1719
 1720    pub fn for_multibuffer(
 1721        buffer: Entity<MultiBuffer>,
 1722        project: Option<Entity<Project>>,
 1723        window: &mut Window,
 1724        cx: &mut Context<Self>,
 1725    ) -> Self {
 1726        Self::new(EditorMode::full(), buffer, project, window, cx)
 1727    }
 1728
 1729    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1730        let mut clone = Self::new(
 1731            self.mode.clone(),
 1732            self.buffer.clone(),
 1733            self.project.clone(),
 1734            window,
 1735            cx,
 1736        );
 1737        self.display_map.update(cx, |display_map, cx| {
 1738            let snapshot = display_map.snapshot(cx);
 1739            clone.display_map.update(cx, |display_map, cx| {
 1740                display_map.set_state(&snapshot, cx);
 1741            });
 1742        });
 1743        clone.folds_did_change(cx);
 1744        clone.selections.clone_state(&self.selections);
 1745        clone.scroll_manager.clone_state(&self.scroll_manager);
 1746        clone.searchable = self.searchable;
 1747        clone.read_only = self.read_only;
 1748        clone
 1749    }
 1750
 1751    pub fn new(
 1752        mode: EditorMode,
 1753        buffer: Entity<MultiBuffer>,
 1754        project: Option<Entity<Project>>,
 1755        window: &mut Window,
 1756        cx: &mut Context<Self>,
 1757    ) -> Self {
 1758        Editor::new_internal(mode, buffer, project, None, window, cx)
 1759    }
 1760
 1761    fn new_internal(
 1762        mode: EditorMode,
 1763        buffer: Entity<MultiBuffer>,
 1764        project: Option<Entity<Project>>,
 1765        display_map: Option<Entity<DisplayMap>>,
 1766        window: &mut Window,
 1767        cx: &mut Context<Self>,
 1768    ) -> Self {
 1769        debug_assert!(
 1770            display_map.is_none() || mode.is_minimap(),
 1771            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1772        );
 1773
 1774        let full_mode = mode.is_full();
 1775        let is_minimap = mode.is_minimap();
 1776        let diagnostics_max_severity = if full_mode {
 1777            EditorSettings::get_global(cx)
 1778                .diagnostics_max_severity
 1779                .unwrap_or(DiagnosticSeverity::Hint)
 1780        } else {
 1781            DiagnosticSeverity::Off
 1782        };
 1783        let style = window.text_style();
 1784        let font_size = style.font_size.to_pixels(window.rem_size());
 1785        let editor = cx.entity().downgrade();
 1786        let fold_placeholder = FoldPlaceholder {
 1787            constrain_width: true,
 1788            render: Arc::new(move |fold_id, fold_range, cx| {
 1789                let editor = editor.clone();
 1790                div()
 1791                    .id(fold_id)
 1792                    .bg(cx.theme().colors().ghost_element_background)
 1793                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1794                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1795                    .rounded_xs()
 1796                    .size_full()
 1797                    .cursor_pointer()
 1798                    .child("")
 1799                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1800                    .on_click(move |_, _window, cx| {
 1801                        editor
 1802                            .update(cx, |editor, cx| {
 1803                                editor.unfold_ranges(
 1804                                    &[fold_range.start..fold_range.end],
 1805                                    true,
 1806                                    false,
 1807                                    cx,
 1808                                );
 1809                                cx.stop_propagation();
 1810                            })
 1811                            .ok();
 1812                    })
 1813                    .into_any()
 1814            }),
 1815            merge_adjacent: true,
 1816            ..FoldPlaceholder::default()
 1817        };
 1818        let display_map = display_map.unwrap_or_else(|| {
 1819            cx.new(|cx| {
 1820                DisplayMap::new(
 1821                    buffer.clone(),
 1822                    style.font(),
 1823                    font_size,
 1824                    None,
 1825                    FILE_HEADER_HEIGHT,
 1826                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1827                    fold_placeholder,
 1828                    diagnostics_max_severity,
 1829                    cx,
 1830                )
 1831            })
 1832        });
 1833
 1834        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1835
 1836        let blink_manager = cx.new(|cx| {
 1837            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1838            if is_minimap {
 1839                blink_manager.disable(cx);
 1840            }
 1841            blink_manager
 1842        });
 1843
 1844        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1845            .then(|| language_settings::SoftWrap::None);
 1846
 1847        let mut project_subscriptions = Vec::new();
 1848        if full_mode {
 1849            if let Some(project) = project.as_ref() {
 1850                project_subscriptions.push(cx.subscribe_in(
 1851                    project,
 1852                    window,
 1853                    |editor, _, event, window, cx| match event {
 1854                        project::Event::RefreshCodeLens => {
 1855                            // we always query lens with actions, without storing them, always refreshing them
 1856                        }
 1857                        project::Event::RefreshInlayHints => {
 1858                            editor
 1859                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1860                        }
 1861                        project::Event::LanguageServerAdded(..)
 1862                        | project::Event::LanguageServerRemoved(..) => {
 1863                            if editor.tasks_update_task.is_none() {
 1864                                editor.tasks_update_task =
 1865                                    Some(editor.refresh_runnables(window, cx));
 1866                            }
 1867                        }
 1868                        project::Event::SnippetEdit(id, snippet_edits) => {
 1869                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1870                                let focus_handle = editor.focus_handle(cx);
 1871                                if focus_handle.is_focused(window) {
 1872                                    let snapshot = buffer.read(cx).snapshot();
 1873                                    for (range, snippet) in snippet_edits {
 1874                                        let editor_range =
 1875                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1876                                        editor
 1877                                            .insert_snippet(
 1878                                                &[editor_range],
 1879                                                snippet.clone(),
 1880                                                window,
 1881                                                cx,
 1882                                            )
 1883                                            .ok();
 1884                                    }
 1885                                }
 1886                            }
 1887                        }
 1888                        project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1889                            if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1890                                editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1891                            }
 1892                        }
 1893                        _ => {}
 1894                    },
 1895                ));
 1896                if let Some(task_inventory) = project
 1897                    .read(cx)
 1898                    .task_store()
 1899                    .read(cx)
 1900                    .task_inventory()
 1901                    .cloned()
 1902                {
 1903                    project_subscriptions.push(cx.observe_in(
 1904                        &task_inventory,
 1905                        window,
 1906                        |editor, _, window, cx| {
 1907                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1908                        },
 1909                    ));
 1910                };
 1911
 1912                project_subscriptions.push(cx.subscribe_in(
 1913                    &project.read(cx).breakpoint_store(),
 1914                    window,
 1915                    |editor, _, event, window, cx| match event {
 1916                        BreakpointStoreEvent::ClearDebugLines => {
 1917                            editor.clear_row_highlights::<ActiveDebugLine>();
 1918                            editor.refresh_inline_values(cx);
 1919                        }
 1920                        BreakpointStoreEvent::SetDebugLine => {
 1921                            if editor.go_to_active_debug_line(window, cx) {
 1922                                cx.stop_propagation();
 1923                            }
 1924
 1925                            editor.refresh_inline_values(cx);
 1926                        }
 1927                        _ => {}
 1928                    },
 1929                ));
 1930                let git_store = project.read(cx).git_store().clone();
 1931                let project = project.clone();
 1932                project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1933                    match event {
 1934                        GitStoreEvent::RepositoryUpdated(
 1935                            _,
 1936                            RepositoryEvent::Updated {
 1937                                new_instance: true, ..
 1938                            },
 1939                            _,
 1940                        ) => {
 1941                            this.load_diff_task = Some(
 1942                                update_uncommitted_diff_for_buffer(
 1943                                    cx.entity(),
 1944                                    &project,
 1945                                    this.buffer.read(cx).all_buffers(),
 1946                                    this.buffer.clone(),
 1947                                    cx,
 1948                                )
 1949                                .shared(),
 1950                            );
 1951                        }
 1952                        _ => {}
 1953                    }
 1954                }));
 1955            }
 1956        }
 1957
 1958        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1959
 1960        let inlay_hint_settings =
 1961            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1962        let focus_handle = cx.focus_handle();
 1963        if !is_minimap {
 1964            cx.on_focus(&focus_handle, window, Self::handle_focus)
 1965                .detach();
 1966            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1967                .detach();
 1968            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1969                .detach();
 1970            cx.on_blur(&focus_handle, window, Self::handle_blur)
 1971                .detach();
 1972            cx.observe_pending_input(window, Self::observe_pending_input)
 1973                .detach();
 1974        }
 1975
 1976        let show_indent_guides = if matches!(
 1977            mode,
 1978            EditorMode::SingleLine { .. } | EditorMode::Minimap { .. }
 1979        ) {
 1980            Some(false)
 1981        } else {
 1982            None
 1983        };
 1984
 1985        let breakpoint_store = match (&mode, project.as_ref()) {
 1986            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1987            _ => None,
 1988        };
 1989
 1990        let mut code_action_providers = Vec::new();
 1991        let mut load_uncommitted_diff = None;
 1992        if let Some(project) = project.clone() {
 1993            load_uncommitted_diff = Some(
 1994                update_uncommitted_diff_for_buffer(
 1995                    cx.entity(),
 1996                    &project,
 1997                    buffer.read(cx).all_buffers(),
 1998                    buffer.clone(),
 1999                    cx,
 2000                )
 2001                .shared(),
 2002            );
 2003            code_action_providers.push(Rc::new(project) as Rc<_>);
 2004        }
 2005
 2006        let mut editor = Self {
 2007            focus_handle,
 2008            show_cursor_when_unfocused: false,
 2009            last_focused_descendant: None,
 2010            buffer: buffer.clone(),
 2011            display_map: display_map.clone(),
 2012            selections,
 2013            scroll_manager: ScrollManager::new(cx),
 2014            columnar_selection_state: None,
 2015            add_selections_state: None,
 2016            select_next_state: None,
 2017            select_prev_state: None,
 2018            selection_history: SelectionHistory::default(),
 2019            defer_selection_effects: false,
 2020            deferred_selection_effects_state: None,
 2021            autoclose_regions: Vec::new(),
 2022            snippet_stack: InvalidationStack::default(),
 2023            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2024            ime_transaction: None,
 2025            active_diagnostics: ActiveDiagnostic::None,
 2026            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2027            inline_diagnostics_update: Task::ready(()),
 2028            inline_diagnostics: Vec::new(),
 2029            soft_wrap_mode_override,
 2030            diagnostics_max_severity,
 2031            hard_wrap: None,
 2032            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2033            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2034            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2035            project,
 2036            blink_manager: blink_manager.clone(),
 2037            show_local_selections: true,
 2038            show_scrollbars: ScrollbarAxes {
 2039                horizontal: full_mode,
 2040                vertical: full_mode,
 2041            },
 2042            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2043            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 2044            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2045            show_gutter: full_mode,
 2046            show_line_numbers: (!full_mode).then_some(false),
 2047            use_relative_line_numbers: None,
 2048            disable_expand_excerpt_buttons: !full_mode,
 2049            show_git_diff_gutter: None,
 2050            show_code_actions: None,
 2051            show_runnables: None,
 2052            show_breakpoints: None,
 2053            show_wrap_guides: None,
 2054            show_indent_guides,
 2055            placeholder_text: None,
 2056            highlight_order: 0,
 2057            highlighted_rows: HashMap::default(),
 2058            background_highlights: TreeMap::default(),
 2059            gutter_highlights: TreeMap::default(),
 2060            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2061            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2062            nav_history: None,
 2063            context_menu: RefCell::new(None),
 2064            context_menu_options: None,
 2065            mouse_context_menu: None,
 2066            completion_tasks: Vec::new(),
 2067            inline_blame_popover: None,
 2068            inline_blame_popover_show_task: None,
 2069            signature_help_state: SignatureHelpState::default(),
 2070            auto_signature_help: None,
 2071            find_all_references_task_sources: Vec::new(),
 2072            next_completion_id: 0,
 2073            next_inlay_id: 0,
 2074            code_action_providers,
 2075            available_code_actions: None,
 2076            code_actions_task: None,
 2077            quick_selection_highlight_task: None,
 2078            debounced_selection_highlight_task: None,
 2079            document_highlights_task: None,
 2080            linked_editing_range_task: None,
 2081            pending_rename: None,
 2082            searchable: !is_minimap,
 2083            cursor_shape: EditorSettings::get_global(cx)
 2084                .cursor_shape
 2085                .unwrap_or_default(),
 2086            current_line_highlight: None,
 2087            autoindent_mode: Some(AutoindentMode::EachLine),
 2088            collapse_matches: false,
 2089            workspace: None,
 2090            input_enabled: !is_minimap,
 2091            use_modal_editing: full_mode,
 2092            read_only: is_minimap,
 2093            use_autoclose: true,
 2094            use_auto_surround: true,
 2095            auto_replace_emoji_shortcode: false,
 2096            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2097            leader_id: None,
 2098            remote_id: None,
 2099            hover_state: HoverState::default(),
 2100            pending_mouse_down: None,
 2101            hovered_link_state: None,
 2102            edit_prediction_provider: None,
 2103            active_edit_prediction: None,
 2104            stale_edit_prediction_in_menu: None,
 2105            edit_prediction_preview: EditPredictionPreview::Inactive {
 2106                released_too_fast: false,
 2107            },
 2108            inline_diagnostics_enabled: full_mode,
 2109            diagnostics_enabled: full_mode,
 2110            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2111            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2112            gutter_hovered: false,
 2113            pixel_position_of_newest_cursor: None,
 2114            last_bounds: None,
 2115            last_position_map: None,
 2116            expect_bounds_change: None,
 2117            gutter_dimensions: GutterDimensions::default(),
 2118            style: None,
 2119            show_cursor_names: false,
 2120            hovered_cursors: HashMap::default(),
 2121            next_editor_action_id: EditorActionId::default(),
 2122            editor_actions: Rc::default(),
 2123            edit_predictions_hidden_for_vim_mode: false,
 2124            show_edit_predictions_override: None,
 2125            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2126            edit_prediction_settings: EditPredictionSettings::Disabled,
 2127            edit_prediction_indent_conflict: false,
 2128            edit_prediction_requires_modifier_in_indent_conflict: true,
 2129            custom_context_menu: None,
 2130            show_git_blame_gutter: false,
 2131            show_git_blame_inline: false,
 2132            show_selection_menu: None,
 2133            show_git_blame_inline_delay_task: None,
 2134            git_blame_inline_enabled: full_mode
 2135                && ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2136            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2137            serialize_dirty_buffers: !is_minimap
 2138                && ProjectSettings::get_global(cx)
 2139                    .session
 2140                    .restore_unsaved_buffers,
 2141            blame: None,
 2142            blame_subscription: None,
 2143            tasks: BTreeMap::default(),
 2144
 2145            breakpoint_store,
 2146            gutter_breakpoint_indicator: (None, None),
 2147            hovered_diff_hunk_row: None,
 2148            _subscriptions: (!is_minimap)
 2149                .then(|| {
 2150                    vec![
 2151                        cx.observe(&buffer, Self::on_buffer_changed),
 2152                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2153                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2154                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2155                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2156                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2157                        cx.observe_window_activation(window, |editor, window, cx| {
 2158                            let active = window.is_window_active();
 2159                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2160                                if active {
 2161                                    blink_manager.enable(cx);
 2162                                } else {
 2163                                    blink_manager.disable(cx);
 2164                                }
 2165                            });
 2166                            if active {
 2167                                editor.show_mouse_cursor(cx);
 2168                            }
 2169                        }),
 2170                    ]
 2171                })
 2172                .unwrap_or_default(),
 2173            tasks_update_task: None,
 2174            pull_diagnostics_task: Task::ready(()),
 2175            colors: None,
 2176            next_color_inlay_id: 0,
 2177            linked_edit_ranges: Default::default(),
 2178            in_project_search: false,
 2179            previous_search_ranges: None,
 2180            breadcrumb_header: None,
 2181            focused_block: None,
 2182            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2183            addons: HashMap::default(),
 2184            registered_buffers: HashMap::default(),
 2185            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2186            selection_mark_mode: false,
 2187            toggle_fold_multiple_buffers: Task::ready(()),
 2188            serialize_selections: Task::ready(()),
 2189            serialize_folds: Task::ready(()),
 2190            text_style_refinement: None,
 2191            load_diff_task: load_uncommitted_diff,
 2192            temporary_diff_override: false,
 2193            mouse_cursor_hidden: false,
 2194            minimap: None,
 2195            hide_mouse_mode: EditorSettings::get_global(cx)
 2196                .hide_mouse
 2197                .unwrap_or_default(),
 2198            change_list: ChangeList::new(),
 2199            mode,
 2200            selection_drag_state: SelectionDragState::None,
 2201            folding_newlines: Task::ready(()),
 2202        };
 2203
 2204        if is_minimap {
 2205            return editor;
 2206        }
 2207
 2208        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2209            editor
 2210                ._subscriptions
 2211                .push(cx.observe(breakpoints, |_, _, cx| {
 2212                    cx.notify();
 2213                }));
 2214        }
 2215        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2216        editor._subscriptions.extend(project_subscriptions);
 2217
 2218        editor._subscriptions.push(cx.subscribe_in(
 2219            &cx.entity(),
 2220            window,
 2221            |editor, _, e: &EditorEvent, window, cx| match e {
 2222                EditorEvent::ScrollPositionChanged { local, .. } => {
 2223                    if *local {
 2224                        let new_anchor = editor.scroll_manager.anchor();
 2225                        let snapshot = editor.snapshot(window, cx);
 2226                        editor.update_restoration_data(cx, move |data| {
 2227                            data.scroll_position = (
 2228                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2229                                new_anchor.offset,
 2230                            );
 2231                        });
 2232                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2233                        editor.inline_blame_popover.take();
 2234                    }
 2235                }
 2236                EditorEvent::Edited { .. } => {
 2237                    if !vim_enabled(cx) {
 2238                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2239                        let pop_state = editor
 2240                            .change_list
 2241                            .last()
 2242                            .map(|previous| {
 2243                                previous.len() == selections.len()
 2244                                    && previous.iter().enumerate().all(|(ix, p)| {
 2245                                        p.to_display_point(&map).row()
 2246                                            == selections[ix].head().row()
 2247                                    })
 2248                            })
 2249                            .unwrap_or(false);
 2250                        let new_positions = selections
 2251                            .into_iter()
 2252                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2253                            .collect();
 2254                        editor
 2255                            .change_list
 2256                            .push_to_change_list(pop_state, new_positions);
 2257                    }
 2258                }
 2259                _ => (),
 2260            },
 2261        ));
 2262
 2263        if let Some(dap_store) = editor
 2264            .project
 2265            .as_ref()
 2266            .map(|project| project.read(cx).dap_store())
 2267        {
 2268            let weak_editor = cx.weak_entity();
 2269
 2270            editor
 2271                ._subscriptions
 2272                .push(
 2273                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2274                        let session_entity = cx.entity();
 2275                        weak_editor
 2276                            .update(cx, |editor, cx| {
 2277                                editor._subscriptions.push(
 2278                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2279                                );
 2280                            })
 2281                            .ok();
 2282                    }),
 2283                );
 2284
 2285            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2286                editor
 2287                    ._subscriptions
 2288                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2289            }
 2290        }
 2291
 2292        // skip adding the initial selection to selection history
 2293        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2294        editor.end_selection(window, cx);
 2295        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2296
 2297        editor.scroll_manager.show_scrollbars(window, cx);
 2298        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2299
 2300        if full_mode {
 2301            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2302            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2303
 2304            if editor.git_blame_inline_enabled {
 2305                editor.start_git_blame_inline(false, window, cx);
 2306            }
 2307
 2308            editor.go_to_active_debug_line(window, cx);
 2309
 2310            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2311                if let Some(project) = editor.project.as_ref() {
 2312                    let handle = project.update(cx, |project, cx| {
 2313                        project.register_buffer_with_language_servers(&buffer, cx)
 2314                    });
 2315                    editor
 2316                        .registered_buffers
 2317                        .insert(buffer.read(cx).remote_id(), handle);
 2318                }
 2319            }
 2320
 2321            editor.minimap =
 2322                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2323            editor.colors = Some(LspColorData::new(cx));
 2324            editor.update_lsp_data(false, None, window, cx);
 2325        }
 2326
 2327        if editor.mode.is_full() {
 2328            editor.report_editor_event("Editor Opened", None, cx);
 2329        }
 2330
 2331        editor
 2332    }
 2333
 2334    pub fn deploy_mouse_context_menu(
 2335        &mut self,
 2336        position: gpui::Point<Pixels>,
 2337        context_menu: Entity<ContextMenu>,
 2338        window: &mut Window,
 2339        cx: &mut Context<Self>,
 2340    ) {
 2341        self.mouse_context_menu = Some(MouseContextMenu::new(
 2342            self,
 2343            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2344            context_menu,
 2345            window,
 2346            cx,
 2347        ));
 2348    }
 2349
 2350    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2351        self.mouse_context_menu
 2352            .as_ref()
 2353            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2354    }
 2355
 2356    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2357        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2358    }
 2359
 2360    fn key_context_internal(
 2361        &self,
 2362        has_active_edit_prediction: bool,
 2363        window: &Window,
 2364        cx: &App,
 2365    ) -> KeyContext {
 2366        let mut key_context = KeyContext::new_with_defaults();
 2367        key_context.add("Editor");
 2368        let mode = match self.mode {
 2369            EditorMode::SingleLine { .. } => "single_line",
 2370            EditorMode::AutoHeight { .. } => "auto_height",
 2371            EditorMode::Minimap { .. } => "minimap",
 2372            EditorMode::Full { .. } => "full",
 2373        };
 2374
 2375        if EditorSettings::jupyter_enabled(cx) {
 2376            key_context.add("jupyter");
 2377        }
 2378
 2379        key_context.set("mode", mode);
 2380        if self.pending_rename.is_some() {
 2381            key_context.add("renaming");
 2382        }
 2383
 2384        match self.context_menu.borrow().as_ref() {
 2385            Some(CodeContextMenu::Completions(menu)) => {
 2386                if menu.visible() {
 2387                    key_context.add("menu");
 2388                    key_context.add("showing_completions");
 2389                }
 2390            }
 2391            Some(CodeContextMenu::CodeActions(menu)) => {
 2392                if menu.visible() {
 2393                    key_context.add("menu");
 2394                    key_context.add("showing_code_actions")
 2395                }
 2396            }
 2397            None => {}
 2398        }
 2399
 2400        if self.signature_help_state.has_multiple_signatures() {
 2401            key_context.add("showing_signature_help");
 2402        }
 2403
 2404        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2405        if !self.focus_handle(cx).contains_focused(window, cx)
 2406            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2407        {
 2408            for addon in self.addons.values() {
 2409                addon.extend_key_context(&mut key_context, cx)
 2410            }
 2411        }
 2412
 2413        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2414            if let Some(extension) = singleton_buffer
 2415                .read(cx)
 2416                .file()
 2417                .and_then(|file| file.path().extension()?.to_str())
 2418            {
 2419                key_context.set("extension", extension.to_string());
 2420            }
 2421        } else {
 2422            key_context.add("multibuffer");
 2423        }
 2424
 2425        if has_active_edit_prediction {
 2426            if self.edit_prediction_in_conflict() {
 2427                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2428            } else {
 2429                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2430                key_context.add("copilot_suggestion");
 2431            }
 2432        }
 2433
 2434        if self.selection_mark_mode {
 2435            key_context.add("selection_mode");
 2436        }
 2437
 2438        key_context
 2439    }
 2440
 2441    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2442        if self.mouse_cursor_hidden {
 2443            self.mouse_cursor_hidden = false;
 2444            cx.notify();
 2445        }
 2446    }
 2447
 2448    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2449        let hide_mouse_cursor = match origin {
 2450            HideMouseCursorOrigin::TypingAction => {
 2451                matches!(
 2452                    self.hide_mouse_mode,
 2453                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2454                )
 2455            }
 2456            HideMouseCursorOrigin::MovementAction => {
 2457                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2458            }
 2459        };
 2460        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2461            self.mouse_cursor_hidden = hide_mouse_cursor;
 2462            cx.notify();
 2463        }
 2464    }
 2465
 2466    pub fn edit_prediction_in_conflict(&self) -> bool {
 2467        if !self.show_edit_predictions_in_menu() {
 2468            return false;
 2469        }
 2470
 2471        let showing_completions = self
 2472            .context_menu
 2473            .borrow()
 2474            .as_ref()
 2475            .map_or(false, |context| {
 2476                matches!(context, CodeContextMenu::Completions(_))
 2477            });
 2478
 2479        showing_completions
 2480            || self.edit_prediction_requires_modifier()
 2481            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2482            // bindings to insert tab characters.
 2483            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2484    }
 2485
 2486    pub fn accept_edit_prediction_keybind(
 2487        &self,
 2488        accept_partial: bool,
 2489        window: &Window,
 2490        cx: &App,
 2491    ) -> AcceptEditPredictionBinding {
 2492        let key_context = self.key_context_internal(true, window, cx);
 2493        let in_conflict = self.edit_prediction_in_conflict();
 2494
 2495        let bindings = if accept_partial {
 2496            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2497        } else {
 2498            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2499        };
 2500
 2501        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2502        // just the first one.
 2503        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2504            !in_conflict
 2505                || binding
 2506                    .keystrokes()
 2507                    .first()
 2508                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2509        }))
 2510    }
 2511
 2512    pub fn new_file(
 2513        workspace: &mut Workspace,
 2514        _: &workspace::NewFile,
 2515        window: &mut Window,
 2516        cx: &mut Context<Workspace>,
 2517    ) {
 2518        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2519            "Failed to create buffer",
 2520            window,
 2521            cx,
 2522            |e, _, _| match e.error_code() {
 2523                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2524                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2525                e.error_tag("required").unwrap_or("the latest version")
 2526            )),
 2527                _ => None,
 2528            },
 2529        );
 2530    }
 2531
 2532    pub fn new_in_workspace(
 2533        workspace: &mut Workspace,
 2534        window: &mut Window,
 2535        cx: &mut Context<Workspace>,
 2536    ) -> Task<Result<Entity<Editor>>> {
 2537        let project = workspace.project().clone();
 2538        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2539
 2540        cx.spawn_in(window, async move |workspace, cx| {
 2541            let buffer = create.await?;
 2542            workspace.update_in(cx, |workspace, window, cx| {
 2543                let editor =
 2544                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2545                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2546                editor
 2547            })
 2548        })
 2549    }
 2550
 2551    fn new_file_vertical(
 2552        workspace: &mut Workspace,
 2553        _: &workspace::NewFileSplitVertical,
 2554        window: &mut Window,
 2555        cx: &mut Context<Workspace>,
 2556    ) {
 2557        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2558    }
 2559
 2560    fn new_file_horizontal(
 2561        workspace: &mut Workspace,
 2562        _: &workspace::NewFileSplitHorizontal,
 2563        window: &mut Window,
 2564        cx: &mut Context<Workspace>,
 2565    ) {
 2566        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2567    }
 2568
 2569    fn new_file_in_direction(
 2570        workspace: &mut Workspace,
 2571        direction: SplitDirection,
 2572        window: &mut Window,
 2573        cx: &mut Context<Workspace>,
 2574    ) {
 2575        let project = workspace.project().clone();
 2576        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2577
 2578        cx.spawn_in(window, async move |workspace, cx| {
 2579            let buffer = create.await?;
 2580            workspace.update_in(cx, move |workspace, window, cx| {
 2581                workspace.split_item(
 2582                    direction,
 2583                    Box::new(
 2584                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2585                    ),
 2586                    window,
 2587                    cx,
 2588                )
 2589            })?;
 2590            anyhow::Ok(())
 2591        })
 2592        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2593            match e.error_code() {
 2594                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2595                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2596                e.error_tag("required").unwrap_or("the latest version")
 2597            )),
 2598                _ => None,
 2599            }
 2600        });
 2601    }
 2602
 2603    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2604        self.leader_id
 2605    }
 2606
 2607    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2608        &self.buffer
 2609    }
 2610
 2611    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2612        self.workspace.as_ref()?.0.upgrade()
 2613    }
 2614
 2615    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2616        self.buffer().read(cx).title(cx)
 2617    }
 2618
 2619    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2620        let git_blame_gutter_max_author_length = self
 2621            .render_git_blame_gutter(cx)
 2622            .then(|| {
 2623                if let Some(blame) = self.blame.as_ref() {
 2624                    let max_author_length =
 2625                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2626                    Some(max_author_length)
 2627                } else {
 2628                    None
 2629                }
 2630            })
 2631            .flatten();
 2632
 2633        EditorSnapshot {
 2634            mode: self.mode.clone(),
 2635            show_gutter: self.show_gutter,
 2636            show_line_numbers: self.show_line_numbers,
 2637            show_git_diff_gutter: self.show_git_diff_gutter,
 2638            show_code_actions: self.show_code_actions,
 2639            show_runnables: self.show_runnables,
 2640            show_breakpoints: self.show_breakpoints,
 2641            git_blame_gutter_max_author_length,
 2642            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2643            scroll_anchor: self.scroll_manager.anchor(),
 2644            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2645            placeholder_text: self.placeholder_text.clone(),
 2646            is_focused: self.focus_handle.is_focused(window),
 2647            current_line_highlight: self
 2648                .current_line_highlight
 2649                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2650            gutter_hovered: self.gutter_hovered,
 2651        }
 2652    }
 2653
 2654    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2655        self.buffer.read(cx).language_at(point, cx)
 2656    }
 2657
 2658    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2659        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2660    }
 2661
 2662    pub fn active_excerpt(
 2663        &self,
 2664        cx: &App,
 2665    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2666        self.buffer
 2667            .read(cx)
 2668            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2669    }
 2670
 2671    pub fn mode(&self) -> &EditorMode {
 2672        &self.mode
 2673    }
 2674
 2675    pub fn set_mode(&mut self, mode: EditorMode) {
 2676        self.mode = mode;
 2677    }
 2678
 2679    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2680        self.collaboration_hub.as_deref()
 2681    }
 2682
 2683    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2684        self.collaboration_hub = Some(hub);
 2685    }
 2686
 2687    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2688        self.in_project_search = in_project_search;
 2689    }
 2690
 2691    pub fn set_custom_context_menu(
 2692        &mut self,
 2693        f: impl 'static
 2694        + Fn(
 2695            &mut Self,
 2696            DisplayPoint,
 2697            &mut Window,
 2698            &mut Context<Self>,
 2699        ) -> Option<Entity<ui::ContextMenu>>,
 2700    ) {
 2701        self.custom_context_menu = Some(Box::new(f))
 2702    }
 2703
 2704    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2705        self.completion_provider = provider;
 2706    }
 2707
 2708    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2709        self.semantics_provider.clone()
 2710    }
 2711
 2712    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2713        self.semantics_provider = provider;
 2714    }
 2715
 2716    pub fn set_edit_prediction_provider<T>(
 2717        &mut self,
 2718        provider: Option<Entity<T>>,
 2719        window: &mut Window,
 2720        cx: &mut Context<Self>,
 2721    ) where
 2722        T: EditPredictionProvider,
 2723    {
 2724        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2725            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2726                if this.focus_handle.is_focused(window) {
 2727                    this.update_visible_edit_prediction(window, cx);
 2728                }
 2729            }),
 2730            provider: Arc::new(provider),
 2731        });
 2732        self.update_edit_prediction_settings(cx);
 2733        self.refresh_edit_prediction(false, false, window, cx);
 2734    }
 2735
 2736    pub fn placeholder_text(&self) -> Option<&str> {
 2737        self.placeholder_text.as_deref()
 2738    }
 2739
 2740    pub fn set_placeholder_text(
 2741        &mut self,
 2742        placeholder_text: impl Into<Arc<str>>,
 2743        cx: &mut Context<Self>,
 2744    ) {
 2745        let placeholder_text = Some(placeholder_text.into());
 2746        if self.placeholder_text != placeholder_text {
 2747            self.placeholder_text = placeholder_text;
 2748            cx.notify();
 2749        }
 2750    }
 2751
 2752    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2753        self.cursor_shape = cursor_shape;
 2754
 2755        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2756        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2757
 2758        cx.notify();
 2759    }
 2760
 2761    pub fn set_current_line_highlight(
 2762        &mut self,
 2763        current_line_highlight: Option<CurrentLineHighlight>,
 2764    ) {
 2765        self.current_line_highlight = current_line_highlight;
 2766    }
 2767
 2768    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2769        self.collapse_matches = collapse_matches;
 2770    }
 2771
 2772    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2773        let buffers = self.buffer.read(cx).all_buffers();
 2774        let Some(project) = self.project.as_ref() else {
 2775            return;
 2776        };
 2777        project.update(cx, |project, cx| {
 2778            for buffer in buffers {
 2779                self.registered_buffers
 2780                    .entry(buffer.read(cx).remote_id())
 2781                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2782            }
 2783        })
 2784    }
 2785
 2786    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2787        if self.collapse_matches {
 2788            return range.start..range.start;
 2789        }
 2790        range.clone()
 2791    }
 2792
 2793    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2794        if self.display_map.read(cx).clip_at_line_ends != clip {
 2795            self.display_map
 2796                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2797        }
 2798    }
 2799
 2800    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2801        self.input_enabled = input_enabled;
 2802    }
 2803
 2804    pub fn set_edit_predictions_hidden_for_vim_mode(
 2805        &mut self,
 2806        hidden: bool,
 2807        window: &mut Window,
 2808        cx: &mut Context<Self>,
 2809    ) {
 2810        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2811            self.edit_predictions_hidden_for_vim_mode = hidden;
 2812            if hidden {
 2813                self.update_visible_edit_prediction(window, cx);
 2814            } else {
 2815                self.refresh_edit_prediction(true, false, window, cx);
 2816            }
 2817        }
 2818    }
 2819
 2820    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2821        self.menu_edit_predictions_policy = value;
 2822    }
 2823
 2824    pub fn set_autoindent(&mut self, autoindent: bool) {
 2825        if autoindent {
 2826            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2827        } else {
 2828            self.autoindent_mode = None;
 2829        }
 2830    }
 2831
 2832    pub fn read_only(&self, cx: &App) -> bool {
 2833        self.read_only || self.buffer.read(cx).read_only()
 2834    }
 2835
 2836    pub fn set_read_only(&mut self, read_only: bool) {
 2837        self.read_only = read_only;
 2838    }
 2839
 2840    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2841        self.use_autoclose = autoclose;
 2842    }
 2843
 2844    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2845        self.use_auto_surround = auto_surround;
 2846    }
 2847
 2848    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2849        self.auto_replace_emoji_shortcode = auto_replace;
 2850    }
 2851
 2852    pub fn toggle_edit_predictions(
 2853        &mut self,
 2854        _: &ToggleEditPrediction,
 2855        window: &mut Window,
 2856        cx: &mut Context<Self>,
 2857    ) {
 2858        if self.show_edit_predictions_override.is_some() {
 2859            self.set_show_edit_predictions(None, window, cx);
 2860        } else {
 2861            let show_edit_predictions = !self.edit_predictions_enabled();
 2862            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2863        }
 2864    }
 2865
 2866    pub fn set_show_edit_predictions(
 2867        &mut self,
 2868        show_edit_predictions: Option<bool>,
 2869        window: &mut Window,
 2870        cx: &mut Context<Self>,
 2871    ) {
 2872        self.show_edit_predictions_override = show_edit_predictions;
 2873        self.update_edit_prediction_settings(cx);
 2874
 2875        if let Some(false) = show_edit_predictions {
 2876            self.discard_edit_prediction(false, cx);
 2877        } else {
 2878            self.refresh_edit_prediction(false, true, window, cx);
 2879        }
 2880    }
 2881
 2882    fn edit_predictions_disabled_in_scope(
 2883        &self,
 2884        buffer: &Entity<Buffer>,
 2885        buffer_position: language::Anchor,
 2886        cx: &App,
 2887    ) -> bool {
 2888        let snapshot = buffer.read(cx).snapshot();
 2889        let settings = snapshot.settings_at(buffer_position, cx);
 2890
 2891        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2892            return false;
 2893        };
 2894
 2895        scope.override_name().map_or(false, |scope_name| {
 2896            settings
 2897                .edit_predictions_disabled_in
 2898                .iter()
 2899                .any(|s| s == scope_name)
 2900        })
 2901    }
 2902
 2903    pub fn set_use_modal_editing(&mut self, to: bool) {
 2904        self.use_modal_editing = to;
 2905    }
 2906
 2907    pub fn use_modal_editing(&self) -> bool {
 2908        self.use_modal_editing
 2909    }
 2910
 2911    fn selections_did_change(
 2912        &mut self,
 2913        local: bool,
 2914        old_cursor_position: &Anchor,
 2915        effects: SelectionEffects,
 2916        window: &mut Window,
 2917        cx: &mut Context<Self>,
 2918    ) {
 2919        window.invalidate_character_coordinates();
 2920
 2921        // Copy selections to primary selection buffer
 2922        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2923        if local {
 2924            let selections = self.selections.all::<usize>(cx);
 2925            let buffer_handle = self.buffer.read(cx).read(cx);
 2926
 2927            let mut text = String::new();
 2928            for (index, selection) in selections.iter().enumerate() {
 2929                let text_for_selection = buffer_handle
 2930                    .text_for_range(selection.start..selection.end)
 2931                    .collect::<String>();
 2932
 2933                text.push_str(&text_for_selection);
 2934                if index != selections.len() - 1 {
 2935                    text.push('\n');
 2936                }
 2937            }
 2938
 2939            if !text.is_empty() {
 2940                cx.write_to_primary(ClipboardItem::new_string(text));
 2941            }
 2942        }
 2943
 2944        let selection_anchors = self.selections.disjoint_anchors();
 2945
 2946        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2947            self.buffer.update(cx, |buffer, cx| {
 2948                buffer.set_active_selections(
 2949                    &selection_anchors,
 2950                    self.selections.line_mode,
 2951                    self.cursor_shape,
 2952                    cx,
 2953                )
 2954            });
 2955        }
 2956        let display_map = self
 2957            .display_map
 2958            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2959        let buffer = &display_map.buffer_snapshot;
 2960        if self.selections.count() == 1 {
 2961            self.add_selections_state = None;
 2962        }
 2963        self.select_next_state = None;
 2964        self.select_prev_state = None;
 2965        self.select_syntax_node_history.try_clear();
 2966        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 2967        self.snippet_stack.invalidate(&selection_anchors, buffer);
 2968        self.take_rename(false, window, cx);
 2969
 2970        let newest_selection = self.selections.newest_anchor();
 2971        let new_cursor_position = newest_selection.head();
 2972        let selection_start = newest_selection.start;
 2973
 2974        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 2975            self.push_to_nav_history(
 2976                *old_cursor_position,
 2977                Some(new_cursor_position.to_point(buffer)),
 2978                false,
 2979                effects.nav_history == Some(true),
 2980                cx,
 2981            );
 2982        }
 2983
 2984        if local {
 2985            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2986                if !self.registered_buffers.contains_key(&buffer_id) {
 2987                    if let Some(project) = self.project.as_ref() {
 2988                        project.update(cx, |project, cx| {
 2989                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2990                                return;
 2991                            };
 2992                            self.registered_buffers.insert(
 2993                                buffer_id,
 2994                                project.register_buffer_with_language_servers(&buffer, cx),
 2995                            );
 2996                        })
 2997                    }
 2998                }
 2999            }
 3000
 3001            let mut context_menu = self.context_menu.borrow_mut();
 3002            let completion_menu = match context_menu.as_ref() {
 3003                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3004                Some(CodeContextMenu::CodeActions(_)) => {
 3005                    *context_menu = None;
 3006                    None
 3007                }
 3008                None => None,
 3009            };
 3010            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3011            drop(context_menu);
 3012
 3013            if effects.completions {
 3014                if let Some(completion_position) = completion_position {
 3015                    let start_offset = selection_start.to_offset(buffer);
 3016                    let position_matches = start_offset == completion_position.to_offset(buffer);
 3017                    let continue_showing = if position_matches {
 3018                        if self.snippet_stack.is_empty() {
 3019                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3020                        } else {
 3021                            // Snippet choices can be shown even when the cursor is in whitespace.
 3022                            // Dismissing the menu with actions like backspace is handled by
 3023                            // invalidation regions.
 3024                            true
 3025                        }
 3026                    } else {
 3027                        false
 3028                    };
 3029
 3030                    if continue_showing {
 3031                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3032                    } else {
 3033                        self.hide_context_menu(window, cx);
 3034                    }
 3035                }
 3036            }
 3037
 3038            hide_hover(self, cx);
 3039
 3040            if old_cursor_position.to_display_point(&display_map).row()
 3041                != new_cursor_position.to_display_point(&display_map).row()
 3042            {
 3043                self.available_code_actions.take();
 3044            }
 3045            self.refresh_code_actions(window, cx);
 3046            self.refresh_document_highlights(cx);
 3047            self.refresh_selected_text_highlights(false, window, cx);
 3048            refresh_matching_bracket_highlights(self, window, cx);
 3049            self.update_visible_edit_prediction(window, cx);
 3050            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3051            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3052            self.inline_blame_popover.take();
 3053            if self.git_blame_inline_enabled {
 3054                self.start_inline_blame_timer(window, cx);
 3055            }
 3056        }
 3057
 3058        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3059        cx.emit(EditorEvent::SelectionsChanged { local });
 3060
 3061        let selections = &self.selections.disjoint;
 3062        if selections.len() == 1 {
 3063            cx.emit(SearchEvent::ActiveMatchChanged)
 3064        }
 3065        if local {
 3066            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3067                let inmemory_selections = selections
 3068                    .iter()
 3069                    .map(|s| {
 3070                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3071                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3072                    })
 3073                    .collect();
 3074                self.update_restoration_data(cx, |data| {
 3075                    data.selections = inmemory_selections;
 3076                });
 3077
 3078                if WorkspaceSettings::get(None, cx).restore_on_startup
 3079                    != RestoreOnStartupBehavior::None
 3080                {
 3081                    if let Some(workspace_id) =
 3082                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 3083                    {
 3084                        let snapshot = self.buffer().read(cx).snapshot(cx);
 3085                        let selections = selections.clone();
 3086                        let background_executor = cx.background_executor().clone();
 3087                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3088                        self.serialize_selections = cx.background_spawn(async move {
 3089                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3090                            let db_selections = selections
 3091                                .iter()
 3092                                .map(|selection| {
 3093                                    (
 3094                                        selection.start.to_offset(&snapshot),
 3095                                        selection.end.to_offset(&snapshot),
 3096                                    )
 3097                                })
 3098                                .collect();
 3099
 3100                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3101                                .await
 3102                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3103                                .log_err();
 3104                        });
 3105                    }
 3106                }
 3107            }
 3108        }
 3109
 3110        cx.notify();
 3111    }
 3112
 3113    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3114        use text::ToOffset as _;
 3115        use text::ToPoint as _;
 3116
 3117        if self.mode.is_minimap()
 3118            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3119        {
 3120            return;
 3121        }
 3122
 3123        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3124            return;
 3125        };
 3126
 3127        let snapshot = singleton.read(cx).snapshot();
 3128        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3129            let display_snapshot = display_map.snapshot(cx);
 3130
 3131            display_snapshot
 3132                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3133                .map(|fold| {
 3134                    fold.range.start.text_anchor.to_point(&snapshot)
 3135                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3136                })
 3137                .collect()
 3138        });
 3139        self.update_restoration_data(cx, |data| {
 3140            data.folds = inmemory_folds;
 3141        });
 3142
 3143        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3144            return;
 3145        };
 3146        let background_executor = cx.background_executor().clone();
 3147        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3148        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3149            display_map
 3150                .snapshot(cx)
 3151                .folds_in_range(0..snapshot.len())
 3152                .map(|fold| {
 3153                    (
 3154                        fold.range.start.text_anchor.to_offset(&snapshot),
 3155                        fold.range.end.text_anchor.to_offset(&snapshot),
 3156                    )
 3157                })
 3158                .collect()
 3159        });
 3160        self.serialize_folds = cx.background_spawn(async move {
 3161            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3162            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3163                .await
 3164                .with_context(|| {
 3165                    format!(
 3166                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3167                    )
 3168                })
 3169                .log_err();
 3170        });
 3171    }
 3172
 3173    pub fn sync_selections(
 3174        &mut self,
 3175        other: Entity<Editor>,
 3176        cx: &mut Context<Self>,
 3177    ) -> gpui::Subscription {
 3178        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3179        self.selections.change_with(cx, |selections| {
 3180            selections.select_anchors(other_selections);
 3181        });
 3182
 3183        let other_subscription =
 3184            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3185                EditorEvent::SelectionsChanged { local: true } => {
 3186                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3187                    if other_selections.is_empty() {
 3188                        return;
 3189                    }
 3190                    this.selections.change_with(cx, |selections| {
 3191                        selections.select_anchors(other_selections);
 3192                    });
 3193                }
 3194                _ => {}
 3195            });
 3196
 3197        let this_subscription =
 3198            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3199                EditorEvent::SelectionsChanged { local: true } => {
 3200                    let these_selections = this.selections.disjoint.to_vec();
 3201                    if these_selections.is_empty() {
 3202                        return;
 3203                    }
 3204                    other.update(cx, |other_editor, cx| {
 3205                        other_editor.selections.change_with(cx, |selections| {
 3206                            selections.select_anchors(these_selections);
 3207                        })
 3208                    });
 3209                }
 3210                _ => {}
 3211            });
 3212
 3213        Subscription::join(other_subscription, this_subscription)
 3214    }
 3215
 3216    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3217    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3218    /// effects of selection change occur at the end of the transaction.
 3219    pub fn change_selections<R>(
 3220        &mut self,
 3221        effects: SelectionEffects,
 3222        window: &mut Window,
 3223        cx: &mut Context<Self>,
 3224        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3225    ) -> R {
 3226        if let Some(state) = &mut self.deferred_selection_effects_state {
 3227            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3228            state.effects.completions = effects.completions;
 3229            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3230            let (changed, result) = self.selections.change_with(cx, change);
 3231            state.changed |= changed;
 3232            return result;
 3233        }
 3234        let mut state = DeferredSelectionEffectsState {
 3235            changed: false,
 3236            effects,
 3237            old_cursor_position: self.selections.newest_anchor().head(),
 3238            history_entry: SelectionHistoryEntry {
 3239                selections: self.selections.disjoint_anchors(),
 3240                select_next_state: self.select_next_state.clone(),
 3241                select_prev_state: self.select_prev_state.clone(),
 3242                add_selections_state: self.add_selections_state.clone(),
 3243            },
 3244        };
 3245        let (changed, result) = self.selections.change_with(cx, change);
 3246        state.changed = state.changed || changed;
 3247        if self.defer_selection_effects {
 3248            self.deferred_selection_effects_state = Some(state);
 3249        } else {
 3250            self.apply_selection_effects(state, window, cx);
 3251        }
 3252        result
 3253    }
 3254
 3255    /// Defers the effects of selection change, so that the effects of multiple calls to
 3256    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3257    /// to selection history and the state of popovers based on selection position aren't
 3258    /// erroneously updated.
 3259    pub fn with_selection_effects_deferred<R>(
 3260        &mut self,
 3261        window: &mut Window,
 3262        cx: &mut Context<Self>,
 3263        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3264    ) -> R {
 3265        let already_deferred = self.defer_selection_effects;
 3266        self.defer_selection_effects = true;
 3267        let result = update(self, window, cx);
 3268        if !already_deferred {
 3269            self.defer_selection_effects = false;
 3270            if let Some(state) = self.deferred_selection_effects_state.take() {
 3271                self.apply_selection_effects(state, window, cx);
 3272            }
 3273        }
 3274        result
 3275    }
 3276
 3277    fn apply_selection_effects(
 3278        &mut self,
 3279        state: DeferredSelectionEffectsState,
 3280        window: &mut Window,
 3281        cx: &mut Context<Self>,
 3282    ) {
 3283        if state.changed {
 3284            self.selection_history.push(state.history_entry);
 3285
 3286            if let Some(autoscroll) = state.effects.scroll {
 3287                self.request_autoscroll(autoscroll, cx);
 3288            }
 3289
 3290            let old_cursor_position = &state.old_cursor_position;
 3291
 3292            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3293
 3294            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3295                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3296            }
 3297        }
 3298    }
 3299
 3300    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3301    where
 3302        I: IntoIterator<Item = (Range<S>, T)>,
 3303        S: ToOffset,
 3304        T: Into<Arc<str>>,
 3305    {
 3306        if self.read_only(cx) {
 3307            return;
 3308        }
 3309
 3310        self.buffer
 3311            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3312    }
 3313
 3314    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3315    where
 3316        I: IntoIterator<Item = (Range<S>, T)>,
 3317        S: ToOffset,
 3318        T: Into<Arc<str>>,
 3319    {
 3320        if self.read_only(cx) {
 3321            return;
 3322        }
 3323
 3324        self.buffer.update(cx, |buffer, cx| {
 3325            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3326        });
 3327    }
 3328
 3329    pub fn edit_with_block_indent<I, S, T>(
 3330        &mut self,
 3331        edits: I,
 3332        original_indent_columns: Vec<Option<u32>>,
 3333        cx: &mut Context<Self>,
 3334    ) where
 3335        I: IntoIterator<Item = (Range<S>, T)>,
 3336        S: ToOffset,
 3337        T: Into<Arc<str>>,
 3338    {
 3339        if self.read_only(cx) {
 3340            return;
 3341        }
 3342
 3343        self.buffer.update(cx, |buffer, cx| {
 3344            buffer.edit(
 3345                edits,
 3346                Some(AutoindentMode::Block {
 3347                    original_indent_columns,
 3348                }),
 3349                cx,
 3350            )
 3351        });
 3352    }
 3353
 3354    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3355        self.hide_context_menu(window, cx);
 3356
 3357        match phase {
 3358            SelectPhase::Begin {
 3359                position,
 3360                add,
 3361                click_count,
 3362            } => self.begin_selection(position, add, click_count, window, cx),
 3363            SelectPhase::BeginColumnar {
 3364                position,
 3365                goal_column,
 3366                reset,
 3367                mode,
 3368            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3369            SelectPhase::Extend {
 3370                position,
 3371                click_count,
 3372            } => self.extend_selection(position, click_count, window, cx),
 3373            SelectPhase::Update {
 3374                position,
 3375                goal_column,
 3376                scroll_delta,
 3377            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3378            SelectPhase::End => self.end_selection(window, cx),
 3379        }
 3380    }
 3381
 3382    fn extend_selection(
 3383        &mut self,
 3384        position: DisplayPoint,
 3385        click_count: usize,
 3386        window: &mut Window,
 3387        cx: &mut Context<Self>,
 3388    ) {
 3389        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3390        let tail = self.selections.newest::<usize>(cx).tail();
 3391        self.begin_selection(position, false, click_count, window, cx);
 3392
 3393        let position = position.to_offset(&display_map, Bias::Left);
 3394        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3395
 3396        let mut pending_selection = self
 3397            .selections
 3398            .pending_anchor()
 3399            .expect("extend_selection not called with pending selection");
 3400        if position >= tail {
 3401            pending_selection.start = tail_anchor;
 3402        } else {
 3403            pending_selection.end = tail_anchor;
 3404            pending_selection.reversed = true;
 3405        }
 3406
 3407        let mut pending_mode = self.selections.pending_mode().unwrap();
 3408        match &mut pending_mode {
 3409            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3410            _ => {}
 3411        }
 3412
 3413        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3414            SelectionEffects::scroll(Autoscroll::fit())
 3415        } else {
 3416            SelectionEffects::no_scroll()
 3417        };
 3418
 3419        self.change_selections(effects, window, cx, |s| {
 3420            s.set_pending(pending_selection, pending_mode)
 3421        });
 3422    }
 3423
 3424    fn begin_selection(
 3425        &mut self,
 3426        position: DisplayPoint,
 3427        add: bool,
 3428        click_count: usize,
 3429        window: &mut Window,
 3430        cx: &mut Context<Self>,
 3431    ) {
 3432        if !self.focus_handle.is_focused(window) {
 3433            self.last_focused_descendant = None;
 3434            window.focus(&self.focus_handle);
 3435        }
 3436
 3437        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3438        let buffer = &display_map.buffer_snapshot;
 3439        let position = display_map.clip_point(position, Bias::Left);
 3440
 3441        let start;
 3442        let end;
 3443        let mode;
 3444        let mut auto_scroll;
 3445        match click_count {
 3446            1 => {
 3447                start = buffer.anchor_before(position.to_point(&display_map));
 3448                end = start;
 3449                mode = SelectMode::Character;
 3450                auto_scroll = true;
 3451            }
 3452            2 => {
 3453                let position = display_map
 3454                    .clip_point(position, Bias::Left)
 3455                    .to_offset(&display_map, Bias::Left);
 3456                let (range, _) = buffer.surrounding_word(position, false);
 3457                start = buffer.anchor_before(range.start);
 3458                end = buffer.anchor_before(range.end);
 3459                mode = SelectMode::Word(start..end);
 3460                auto_scroll = true;
 3461            }
 3462            3 => {
 3463                let position = display_map
 3464                    .clip_point(position, Bias::Left)
 3465                    .to_point(&display_map);
 3466                let line_start = display_map.prev_line_boundary(position).0;
 3467                let next_line_start = buffer.clip_point(
 3468                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3469                    Bias::Left,
 3470                );
 3471                start = buffer.anchor_before(line_start);
 3472                end = buffer.anchor_before(next_line_start);
 3473                mode = SelectMode::Line(start..end);
 3474                auto_scroll = true;
 3475            }
 3476            _ => {
 3477                start = buffer.anchor_before(0);
 3478                end = buffer.anchor_before(buffer.len());
 3479                mode = SelectMode::All;
 3480                auto_scroll = false;
 3481            }
 3482        }
 3483        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3484
 3485        let point_to_delete: Option<usize> = {
 3486            let selected_points: Vec<Selection<Point>> =
 3487                self.selections.disjoint_in_range(start..end, cx);
 3488
 3489            if !add || click_count > 1 {
 3490                None
 3491            } else if !selected_points.is_empty() {
 3492                Some(selected_points[0].id)
 3493            } else {
 3494                let clicked_point_already_selected =
 3495                    self.selections.disjoint.iter().find(|selection| {
 3496                        selection.start.to_point(buffer) == start.to_point(buffer)
 3497                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3498                    });
 3499
 3500                clicked_point_already_selected.map(|selection| selection.id)
 3501            }
 3502        };
 3503
 3504        let selections_count = self.selections.count();
 3505        let effects = if auto_scroll {
 3506            SelectionEffects::default()
 3507        } else {
 3508            SelectionEffects::no_scroll()
 3509        };
 3510
 3511        self.change_selections(effects, window, cx, |s| {
 3512            if let Some(point_to_delete) = point_to_delete {
 3513                s.delete(point_to_delete);
 3514
 3515                if selections_count == 1 {
 3516                    s.set_pending_anchor_range(start..end, mode);
 3517                }
 3518            } else {
 3519                if !add {
 3520                    s.clear_disjoint();
 3521                }
 3522
 3523                s.set_pending_anchor_range(start..end, mode);
 3524            }
 3525        });
 3526    }
 3527
 3528    fn begin_columnar_selection(
 3529        &mut self,
 3530        position: DisplayPoint,
 3531        goal_column: u32,
 3532        reset: bool,
 3533        mode: ColumnarMode,
 3534        window: &mut Window,
 3535        cx: &mut Context<Self>,
 3536    ) {
 3537        if !self.focus_handle.is_focused(window) {
 3538            self.last_focused_descendant = None;
 3539            window.focus(&self.focus_handle);
 3540        }
 3541
 3542        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3543
 3544        if reset {
 3545            let pointer_position = display_map
 3546                .buffer_snapshot
 3547                .anchor_before(position.to_point(&display_map));
 3548
 3549            self.change_selections(
 3550                SelectionEffects::scroll(Autoscroll::newest()),
 3551                window,
 3552                cx,
 3553                |s| {
 3554                    s.clear_disjoint();
 3555                    s.set_pending_anchor_range(
 3556                        pointer_position..pointer_position,
 3557                        SelectMode::Character,
 3558                    );
 3559                },
 3560            );
 3561        };
 3562
 3563        let tail = self.selections.newest::<Point>(cx).tail();
 3564        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3565        self.columnar_selection_state = match mode {
 3566            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3567                selection_tail: selection_anchor,
 3568                display_point: if reset {
 3569                    if position.column() != goal_column {
 3570                        Some(DisplayPoint::new(position.row(), goal_column))
 3571                    } else {
 3572                        None
 3573                    }
 3574                } else {
 3575                    None
 3576                },
 3577            }),
 3578            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3579                selection_tail: selection_anchor,
 3580            }),
 3581        };
 3582
 3583        if !reset {
 3584            self.select_columns(position, goal_column, &display_map, window, cx);
 3585        }
 3586    }
 3587
 3588    fn update_selection(
 3589        &mut self,
 3590        position: DisplayPoint,
 3591        goal_column: u32,
 3592        scroll_delta: gpui::Point<f32>,
 3593        window: &mut Window,
 3594        cx: &mut Context<Self>,
 3595    ) {
 3596        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3597
 3598        if self.columnar_selection_state.is_some() {
 3599            self.select_columns(position, goal_column, &display_map, window, cx);
 3600        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3601            let buffer = &display_map.buffer_snapshot;
 3602            let head;
 3603            let tail;
 3604            let mode = self.selections.pending_mode().unwrap();
 3605            match &mode {
 3606                SelectMode::Character => {
 3607                    head = position.to_point(&display_map);
 3608                    tail = pending.tail().to_point(buffer);
 3609                }
 3610                SelectMode::Word(original_range) => {
 3611                    let offset = display_map
 3612                        .clip_point(position, Bias::Left)
 3613                        .to_offset(&display_map, Bias::Left);
 3614                    let original_range = original_range.to_offset(buffer);
 3615
 3616                    let head_offset = if buffer.is_inside_word(offset, false)
 3617                        || original_range.contains(&offset)
 3618                    {
 3619                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3620                        if word_range.start < original_range.start {
 3621                            word_range.start
 3622                        } else {
 3623                            word_range.end
 3624                        }
 3625                    } else {
 3626                        offset
 3627                    };
 3628
 3629                    head = head_offset.to_point(buffer);
 3630                    if head_offset <= original_range.start {
 3631                        tail = original_range.end.to_point(buffer);
 3632                    } else {
 3633                        tail = original_range.start.to_point(buffer);
 3634                    }
 3635                }
 3636                SelectMode::Line(original_range) => {
 3637                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3638
 3639                    let position = display_map
 3640                        .clip_point(position, Bias::Left)
 3641                        .to_point(&display_map);
 3642                    let line_start = display_map.prev_line_boundary(position).0;
 3643                    let next_line_start = buffer.clip_point(
 3644                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3645                        Bias::Left,
 3646                    );
 3647
 3648                    if line_start < original_range.start {
 3649                        head = line_start
 3650                    } else {
 3651                        head = next_line_start
 3652                    }
 3653
 3654                    if head <= original_range.start {
 3655                        tail = original_range.end;
 3656                    } else {
 3657                        tail = original_range.start;
 3658                    }
 3659                }
 3660                SelectMode::All => {
 3661                    return;
 3662                }
 3663            };
 3664
 3665            if head < tail {
 3666                pending.start = buffer.anchor_before(head);
 3667                pending.end = buffer.anchor_before(tail);
 3668                pending.reversed = true;
 3669            } else {
 3670                pending.start = buffer.anchor_before(tail);
 3671                pending.end = buffer.anchor_before(head);
 3672                pending.reversed = false;
 3673            }
 3674
 3675            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3676                s.set_pending(pending, mode);
 3677            });
 3678        } else {
 3679            log::error!("update_selection dispatched with no pending selection");
 3680            return;
 3681        }
 3682
 3683        self.apply_scroll_delta(scroll_delta, window, cx);
 3684        cx.notify();
 3685    }
 3686
 3687    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3688        self.columnar_selection_state.take();
 3689        if self.selections.pending_anchor().is_some() {
 3690            let selections = self.selections.all::<usize>(cx);
 3691            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3692                s.select(selections);
 3693                s.clear_pending();
 3694            });
 3695        }
 3696    }
 3697
 3698    fn select_columns(
 3699        &mut self,
 3700        head: DisplayPoint,
 3701        goal_column: u32,
 3702        display_map: &DisplaySnapshot,
 3703        window: &mut Window,
 3704        cx: &mut Context<Self>,
 3705    ) {
 3706        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3707            return;
 3708        };
 3709
 3710        let tail = match columnar_state {
 3711            ColumnarSelectionState::FromMouse {
 3712                selection_tail,
 3713                display_point,
 3714            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(&display_map)),
 3715            ColumnarSelectionState::FromSelection { selection_tail } => {
 3716                selection_tail.to_display_point(&display_map)
 3717            }
 3718        };
 3719
 3720        let start_row = cmp::min(tail.row(), head.row());
 3721        let end_row = cmp::max(tail.row(), head.row());
 3722        let start_column = cmp::min(tail.column(), goal_column);
 3723        let end_column = cmp::max(tail.column(), goal_column);
 3724        let reversed = start_column < tail.column();
 3725
 3726        let selection_ranges = (start_row.0..=end_row.0)
 3727            .map(DisplayRow)
 3728            .filter_map(|row| {
 3729                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3730                    || start_column <= display_map.line_len(row))
 3731                    && !display_map.is_block_line(row)
 3732                {
 3733                    let start = display_map
 3734                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3735                        .to_point(display_map);
 3736                    let end = display_map
 3737                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3738                        .to_point(display_map);
 3739                    if reversed {
 3740                        Some(end..start)
 3741                    } else {
 3742                        Some(start..end)
 3743                    }
 3744                } else {
 3745                    None
 3746                }
 3747            })
 3748            .collect::<Vec<_>>();
 3749
 3750        let ranges = match columnar_state {
 3751            ColumnarSelectionState::FromMouse { .. } => {
 3752                let mut non_empty_ranges = selection_ranges
 3753                    .iter()
 3754                    .filter(|selection_range| selection_range.start != selection_range.end)
 3755                    .peekable();
 3756                if non_empty_ranges.peek().is_some() {
 3757                    non_empty_ranges.cloned().collect()
 3758                } else {
 3759                    selection_ranges
 3760                }
 3761            }
 3762            _ => selection_ranges,
 3763        };
 3764
 3765        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3766            s.select_ranges(ranges);
 3767        });
 3768        cx.notify();
 3769    }
 3770
 3771    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3772        self.selections
 3773            .all_adjusted(cx)
 3774            .iter()
 3775            .any(|selection| !selection.is_empty())
 3776    }
 3777
 3778    pub fn has_pending_nonempty_selection(&self) -> bool {
 3779        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3780            Some(Selection { start, end, .. }) => start != end,
 3781            None => false,
 3782        };
 3783
 3784        pending_nonempty_selection
 3785            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3786    }
 3787
 3788    pub fn has_pending_selection(&self) -> bool {
 3789        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3790    }
 3791
 3792    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3793        self.selection_mark_mode = false;
 3794        self.selection_drag_state = SelectionDragState::None;
 3795
 3796        if self.clear_expanded_diff_hunks(cx) {
 3797            cx.notify();
 3798            return;
 3799        }
 3800        if self.dismiss_menus_and_popups(true, window, cx) {
 3801            return;
 3802        }
 3803
 3804        if self.mode.is_full()
 3805            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3806        {
 3807            return;
 3808        }
 3809
 3810        cx.propagate();
 3811    }
 3812
 3813    pub fn dismiss_menus_and_popups(
 3814        &mut self,
 3815        is_user_requested: bool,
 3816        window: &mut Window,
 3817        cx: &mut Context<Self>,
 3818    ) -> bool {
 3819        if self.take_rename(false, window, cx).is_some() {
 3820            return true;
 3821        }
 3822
 3823        if hide_hover(self, cx) {
 3824            return true;
 3825        }
 3826
 3827        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3828            return true;
 3829        }
 3830
 3831        if self.hide_context_menu(window, cx).is_some() {
 3832            return true;
 3833        }
 3834
 3835        if self.mouse_context_menu.take().is_some() {
 3836            return true;
 3837        }
 3838
 3839        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3840            return true;
 3841        }
 3842
 3843        if self.snippet_stack.pop().is_some() {
 3844            return true;
 3845        }
 3846
 3847        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3848            self.dismiss_diagnostics(cx);
 3849            return true;
 3850        }
 3851
 3852        false
 3853    }
 3854
 3855    fn linked_editing_ranges_for(
 3856        &self,
 3857        selection: Range<text::Anchor>,
 3858        cx: &App,
 3859    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3860        if self.linked_edit_ranges.is_empty() {
 3861            return None;
 3862        }
 3863        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3864            selection.end.buffer_id.and_then(|end_buffer_id| {
 3865                if selection.start.buffer_id != Some(end_buffer_id) {
 3866                    return None;
 3867                }
 3868                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3869                let snapshot = buffer.read(cx).snapshot();
 3870                self.linked_edit_ranges
 3871                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3872                    .map(|ranges| (ranges, snapshot, buffer))
 3873            })?;
 3874        use text::ToOffset as TO;
 3875        // find offset from the start of current range to current cursor position
 3876        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3877
 3878        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3879        let start_difference = start_offset - start_byte_offset;
 3880        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3881        let end_difference = end_offset - start_byte_offset;
 3882        // Current range has associated linked ranges.
 3883        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3884        for range in linked_ranges.iter() {
 3885            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3886            let end_offset = start_offset + end_difference;
 3887            let start_offset = start_offset + start_difference;
 3888            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3889                continue;
 3890            }
 3891            if self.selections.disjoint_anchor_ranges().any(|s| {
 3892                if s.start.buffer_id != selection.start.buffer_id
 3893                    || s.end.buffer_id != selection.end.buffer_id
 3894                {
 3895                    return false;
 3896                }
 3897                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3898                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3899            }) {
 3900                continue;
 3901            }
 3902            let start = buffer_snapshot.anchor_after(start_offset);
 3903            let end = buffer_snapshot.anchor_after(end_offset);
 3904            linked_edits
 3905                .entry(buffer.clone())
 3906                .or_default()
 3907                .push(start..end);
 3908        }
 3909        Some(linked_edits)
 3910    }
 3911
 3912    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3913        let text: Arc<str> = text.into();
 3914
 3915        if self.read_only(cx) {
 3916            return;
 3917        }
 3918
 3919        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3920
 3921        let selections = self.selections.all_adjusted(cx);
 3922        let mut bracket_inserted = false;
 3923        let mut edits = Vec::new();
 3924        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3925        let mut new_selections = Vec::with_capacity(selections.len());
 3926        let mut new_autoclose_regions = Vec::new();
 3927        let snapshot = self.buffer.read(cx).read(cx);
 3928        let mut clear_linked_edit_ranges = false;
 3929
 3930        for (selection, autoclose_region) in
 3931            self.selections_with_autoclose_regions(selections, &snapshot)
 3932        {
 3933            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3934                // Determine if the inserted text matches the opening or closing
 3935                // bracket of any of this language's bracket pairs.
 3936                let mut bracket_pair = None;
 3937                let mut is_bracket_pair_start = false;
 3938                let mut is_bracket_pair_end = false;
 3939                if !text.is_empty() {
 3940                    let mut bracket_pair_matching_end = None;
 3941                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3942                    //  and they are removing the character that triggered IME popup.
 3943                    for (pair, enabled) in scope.brackets() {
 3944                        if !pair.close && !pair.surround {
 3945                            continue;
 3946                        }
 3947
 3948                        if enabled && pair.start.ends_with(text.as_ref()) {
 3949                            let prefix_len = pair.start.len() - text.len();
 3950                            let preceding_text_matches_prefix = prefix_len == 0
 3951                                || (selection.start.column >= (prefix_len as u32)
 3952                                    && snapshot.contains_str_at(
 3953                                        Point::new(
 3954                                            selection.start.row,
 3955                                            selection.start.column - (prefix_len as u32),
 3956                                        ),
 3957                                        &pair.start[..prefix_len],
 3958                                    ));
 3959                            if preceding_text_matches_prefix {
 3960                                bracket_pair = Some(pair.clone());
 3961                                is_bracket_pair_start = true;
 3962                                break;
 3963                            }
 3964                        }
 3965                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3966                        {
 3967                            // take first bracket pair matching end, but don't break in case a later bracket
 3968                            // pair matches start
 3969                            bracket_pair_matching_end = Some(pair.clone());
 3970                        }
 3971                    }
 3972                    if let Some(end) = bracket_pair_matching_end
 3973                        && bracket_pair.is_none()
 3974                    {
 3975                        bracket_pair = Some(end);
 3976                        is_bracket_pair_end = true;
 3977                    }
 3978                }
 3979
 3980                if let Some(bracket_pair) = bracket_pair {
 3981                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3982                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3983                    let auto_surround =
 3984                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3985                    if selection.is_empty() {
 3986                        if is_bracket_pair_start {
 3987                            // If the inserted text is a suffix of an opening bracket and the
 3988                            // selection is preceded by the rest of the opening bracket, then
 3989                            // insert the closing bracket.
 3990                            let following_text_allows_autoclose = snapshot
 3991                                .chars_at(selection.start)
 3992                                .next()
 3993                                .map_or(true, |c| scope.should_autoclose_before(c));
 3994
 3995                            let preceding_text_allows_autoclose = selection.start.column == 0
 3996                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3997                                    true,
 3998                                    |c| {
 3999                                        bracket_pair.start != bracket_pair.end
 4000                                            || !snapshot
 4001                                                .char_classifier_at(selection.start)
 4002                                                .is_word(c)
 4003                                    },
 4004                                );
 4005
 4006                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4007                                && bracket_pair.start.len() == 1
 4008                            {
 4009                                let target = bracket_pair.start.chars().next().unwrap();
 4010                                let current_line_count = snapshot
 4011                                    .reversed_chars_at(selection.start)
 4012                                    .take_while(|&c| c != '\n')
 4013                                    .filter(|&c| c == target)
 4014                                    .count();
 4015                                current_line_count % 2 == 1
 4016                            } else {
 4017                                false
 4018                            };
 4019
 4020                            if autoclose
 4021                                && bracket_pair.close
 4022                                && following_text_allows_autoclose
 4023                                && preceding_text_allows_autoclose
 4024                                && !is_closing_quote
 4025                            {
 4026                                let anchor = snapshot.anchor_before(selection.end);
 4027                                new_selections.push((selection.map(|_| anchor), text.len()));
 4028                                new_autoclose_regions.push((
 4029                                    anchor,
 4030                                    text.len(),
 4031                                    selection.id,
 4032                                    bracket_pair.clone(),
 4033                                ));
 4034                                edits.push((
 4035                                    selection.range(),
 4036                                    format!("{}{}", text, bracket_pair.end).into(),
 4037                                ));
 4038                                bracket_inserted = true;
 4039                                continue;
 4040                            }
 4041                        }
 4042
 4043                        if let Some(region) = autoclose_region {
 4044                            // If the selection is followed by an auto-inserted closing bracket,
 4045                            // then don't insert that closing bracket again; just move the selection
 4046                            // past the closing bracket.
 4047                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4048                                && text.as_ref() == region.pair.end.as_str()
 4049                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4050                            if should_skip {
 4051                                let anchor = snapshot.anchor_after(selection.end);
 4052                                new_selections
 4053                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4054                                continue;
 4055                            }
 4056                        }
 4057
 4058                        let always_treat_brackets_as_autoclosed = snapshot
 4059                            .language_settings_at(selection.start, cx)
 4060                            .always_treat_brackets_as_autoclosed;
 4061                        if always_treat_brackets_as_autoclosed
 4062                            && is_bracket_pair_end
 4063                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4064                        {
 4065                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4066                            // and the inserted text is a closing bracket and the selection is followed
 4067                            // by the closing bracket then move the selection past the closing bracket.
 4068                            let anchor = snapshot.anchor_after(selection.end);
 4069                            new_selections.push((selection.map(|_| anchor), text.len()));
 4070                            continue;
 4071                        }
 4072                    }
 4073                    // If an opening bracket is 1 character long and is typed while
 4074                    // text is selected, then surround that text with the bracket pair.
 4075                    else if auto_surround
 4076                        && bracket_pair.surround
 4077                        && is_bracket_pair_start
 4078                        && bracket_pair.start.chars().count() == 1
 4079                    {
 4080                        edits.push((selection.start..selection.start, text.clone()));
 4081                        edits.push((
 4082                            selection.end..selection.end,
 4083                            bracket_pair.end.as_str().into(),
 4084                        ));
 4085                        bracket_inserted = true;
 4086                        new_selections.push((
 4087                            Selection {
 4088                                id: selection.id,
 4089                                start: snapshot.anchor_after(selection.start),
 4090                                end: snapshot.anchor_before(selection.end),
 4091                                reversed: selection.reversed,
 4092                                goal: selection.goal,
 4093                            },
 4094                            0,
 4095                        ));
 4096                        continue;
 4097                    }
 4098                }
 4099            }
 4100
 4101            if self.auto_replace_emoji_shortcode
 4102                && selection.is_empty()
 4103                && text.as_ref().ends_with(':')
 4104            {
 4105                if let Some(possible_emoji_short_code) =
 4106                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4107                {
 4108                    if !possible_emoji_short_code.is_empty() {
 4109                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 4110                            let emoji_shortcode_start = Point::new(
 4111                                selection.start.row,
 4112                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4113                            );
 4114
 4115                            // Remove shortcode from buffer
 4116                            edits.push((
 4117                                emoji_shortcode_start..selection.start,
 4118                                "".to_string().into(),
 4119                            ));
 4120                            new_selections.push((
 4121                                Selection {
 4122                                    id: selection.id,
 4123                                    start: snapshot.anchor_after(emoji_shortcode_start),
 4124                                    end: snapshot.anchor_before(selection.start),
 4125                                    reversed: selection.reversed,
 4126                                    goal: selection.goal,
 4127                                },
 4128                                0,
 4129                            ));
 4130
 4131                            // Insert emoji
 4132                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 4133                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4134                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 4135
 4136                            continue;
 4137                        }
 4138                    }
 4139                }
 4140            }
 4141
 4142            // If not handling any auto-close operation, then just replace the selected
 4143            // text with the given input and move the selection to the end of the
 4144            // newly inserted text.
 4145            let anchor = snapshot.anchor_after(selection.end);
 4146            if !self.linked_edit_ranges.is_empty() {
 4147                let start_anchor = snapshot.anchor_before(selection.start);
 4148
 4149                let is_word_char = text.chars().next().map_or(true, |char| {
 4150                    let classifier = snapshot
 4151                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4152                        .ignore_punctuation(true);
 4153                    classifier.is_word(char)
 4154                });
 4155
 4156                if is_word_char {
 4157                    if let Some(ranges) = self
 4158                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4159                    {
 4160                        for (buffer, edits) in ranges {
 4161                            linked_edits
 4162                                .entry(buffer.clone())
 4163                                .or_default()
 4164                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4165                        }
 4166                    }
 4167                } else {
 4168                    clear_linked_edit_ranges = true;
 4169                }
 4170            }
 4171
 4172            new_selections.push((selection.map(|_| anchor), 0));
 4173            edits.push((selection.start..selection.end, text.clone()));
 4174        }
 4175
 4176        drop(snapshot);
 4177
 4178        self.transact(window, cx, |this, window, cx| {
 4179            if clear_linked_edit_ranges {
 4180                this.linked_edit_ranges.clear();
 4181            }
 4182            let initial_buffer_versions =
 4183                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4184
 4185            this.buffer.update(cx, |buffer, cx| {
 4186                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4187            });
 4188            for (buffer, edits) in linked_edits {
 4189                buffer.update(cx, |buffer, cx| {
 4190                    let snapshot = buffer.snapshot();
 4191                    let edits = edits
 4192                        .into_iter()
 4193                        .map(|(range, text)| {
 4194                            use text::ToPoint as TP;
 4195                            let end_point = TP::to_point(&range.end, &snapshot);
 4196                            let start_point = TP::to_point(&range.start, &snapshot);
 4197                            (start_point..end_point, text)
 4198                        })
 4199                        .sorted_by_key(|(range, _)| range.start);
 4200                    buffer.edit(edits, None, cx);
 4201                })
 4202            }
 4203            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4204            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4205            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4206            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4207                .zip(new_selection_deltas)
 4208                .map(|(selection, delta)| Selection {
 4209                    id: selection.id,
 4210                    start: selection.start + delta,
 4211                    end: selection.end + delta,
 4212                    reversed: selection.reversed,
 4213                    goal: SelectionGoal::None,
 4214                })
 4215                .collect::<Vec<_>>();
 4216
 4217            let mut i = 0;
 4218            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4219                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4220                let start = map.buffer_snapshot.anchor_before(position);
 4221                let end = map.buffer_snapshot.anchor_after(position);
 4222                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4223                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4224                        Ordering::Less => i += 1,
 4225                        Ordering::Greater => break,
 4226                        Ordering::Equal => {
 4227                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4228                                Ordering::Less => i += 1,
 4229                                Ordering::Equal => break,
 4230                                Ordering::Greater => break,
 4231                            }
 4232                        }
 4233                    }
 4234                }
 4235                this.autoclose_regions.insert(
 4236                    i,
 4237                    AutocloseRegion {
 4238                        selection_id,
 4239                        range: start..end,
 4240                        pair,
 4241                    },
 4242                );
 4243            }
 4244
 4245            let had_active_edit_prediction = this.has_active_edit_prediction();
 4246            this.change_selections(
 4247                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4248                window,
 4249                cx,
 4250                |s| s.select(new_selections),
 4251            );
 4252
 4253            if !bracket_inserted {
 4254                if let Some(on_type_format_task) =
 4255                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4256                {
 4257                    on_type_format_task.detach_and_log_err(cx);
 4258                }
 4259            }
 4260
 4261            let editor_settings = EditorSettings::get_global(cx);
 4262            if bracket_inserted
 4263                && (editor_settings.auto_signature_help
 4264                    || editor_settings.show_signature_help_after_edits)
 4265            {
 4266                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4267            }
 4268
 4269            let trigger_in_words =
 4270                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4271            if this.hard_wrap.is_some() {
 4272                let latest: Range<Point> = this.selections.newest(cx).range();
 4273                if latest.is_empty()
 4274                    && this
 4275                        .buffer()
 4276                        .read(cx)
 4277                        .snapshot(cx)
 4278                        .line_len(MultiBufferRow(latest.start.row))
 4279                        == latest.start.column
 4280                {
 4281                    this.rewrap_impl(
 4282                        RewrapOptions {
 4283                            override_language_settings: true,
 4284                            preserve_existing_whitespace: true,
 4285                        },
 4286                        cx,
 4287                    )
 4288                }
 4289            }
 4290            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4291            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4292            this.refresh_edit_prediction(true, false, window, cx);
 4293            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4294        });
 4295    }
 4296
 4297    fn find_possible_emoji_shortcode_at_position(
 4298        snapshot: &MultiBufferSnapshot,
 4299        position: Point,
 4300    ) -> Option<String> {
 4301        let mut chars = Vec::new();
 4302        let mut found_colon = false;
 4303        for char in snapshot.reversed_chars_at(position).take(100) {
 4304            // Found a possible emoji shortcode in the middle of the buffer
 4305            if found_colon {
 4306                if char.is_whitespace() {
 4307                    chars.reverse();
 4308                    return Some(chars.iter().collect());
 4309                }
 4310                // If the previous character is not a whitespace, we are in the middle of a word
 4311                // and we only want to complete the shortcode if the word is made up of other emojis
 4312                let mut containing_word = String::new();
 4313                for ch in snapshot
 4314                    .reversed_chars_at(position)
 4315                    .skip(chars.len() + 1)
 4316                    .take(100)
 4317                {
 4318                    if ch.is_whitespace() {
 4319                        break;
 4320                    }
 4321                    containing_word.push(ch);
 4322                }
 4323                let containing_word = containing_word.chars().rev().collect::<String>();
 4324                if util::word_consists_of_emojis(containing_word.as_str()) {
 4325                    chars.reverse();
 4326                    return Some(chars.iter().collect());
 4327                }
 4328            }
 4329
 4330            if char.is_whitespace() || !char.is_ascii() {
 4331                return None;
 4332            }
 4333            if char == ':' {
 4334                found_colon = true;
 4335            } else {
 4336                chars.push(char);
 4337            }
 4338        }
 4339        // Found a possible emoji shortcode at the beginning of the buffer
 4340        chars.reverse();
 4341        Some(chars.iter().collect())
 4342    }
 4343
 4344    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4345        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4346        self.transact(window, cx, |this, window, cx| {
 4347            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4348                let selections = this.selections.all::<usize>(cx);
 4349                let multi_buffer = this.buffer.read(cx);
 4350                let buffer = multi_buffer.snapshot(cx);
 4351                selections
 4352                    .iter()
 4353                    .map(|selection| {
 4354                        let start_point = selection.start.to_point(&buffer);
 4355                        let mut existing_indent =
 4356                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4357                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4358                        let start = selection.start;
 4359                        let end = selection.end;
 4360                        let selection_is_empty = start == end;
 4361                        let language_scope = buffer.language_scope_at(start);
 4362                        let (
 4363                            comment_delimiter,
 4364                            doc_delimiter,
 4365                            insert_extra_newline,
 4366                            indent_on_newline,
 4367                            indent_on_extra_newline,
 4368                        ) = if let Some(language) = &language_scope {
 4369                            let mut insert_extra_newline =
 4370                                insert_extra_newline_brackets(&buffer, start..end, language)
 4371                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4372
 4373                            // Comment extension on newline is allowed only for cursor selections
 4374                            let comment_delimiter = maybe!({
 4375                                if !selection_is_empty {
 4376                                    return None;
 4377                                }
 4378
 4379                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4380                                    return None;
 4381                                }
 4382
 4383                                let delimiters = language.line_comment_prefixes();
 4384                                let max_len_of_delimiter =
 4385                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4386                                let (snapshot, range) =
 4387                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4388
 4389                                let num_of_whitespaces = snapshot
 4390                                    .chars_for_range(range.clone())
 4391                                    .take_while(|c| c.is_whitespace())
 4392                                    .count();
 4393                                let comment_candidate = snapshot
 4394                                    .chars_for_range(range.clone())
 4395                                    .skip(num_of_whitespaces)
 4396                                    .take(max_len_of_delimiter)
 4397                                    .collect::<String>();
 4398                                let (delimiter, trimmed_len) = delimiters
 4399                                    .iter()
 4400                                    .filter_map(|delimiter| {
 4401                                        let prefix = delimiter.trim_end();
 4402                                        if comment_candidate.starts_with(prefix) {
 4403                                            Some((delimiter, prefix.len()))
 4404                                        } else {
 4405                                            None
 4406                                        }
 4407                                    })
 4408                                    .max_by_key(|(_, len)| *len)?;
 4409
 4410                                if let Some(BlockCommentConfig {
 4411                                    start: block_start, ..
 4412                                }) = language.block_comment()
 4413                                {
 4414                                    let block_start_trimmed = block_start.trim_end();
 4415                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4416                                        let line_content = snapshot
 4417                                            .chars_for_range(range)
 4418                                            .skip(num_of_whitespaces)
 4419                                            .take(block_start_trimmed.len())
 4420                                            .collect::<String>();
 4421
 4422                                        if line_content.starts_with(block_start_trimmed) {
 4423                                            return None;
 4424                                        }
 4425                                    }
 4426                                }
 4427
 4428                                let cursor_is_placed_after_comment_marker =
 4429                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4430                                if cursor_is_placed_after_comment_marker {
 4431                                    Some(delimiter.clone())
 4432                                } else {
 4433                                    None
 4434                                }
 4435                            });
 4436
 4437                            let mut indent_on_newline = IndentSize::spaces(0);
 4438                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4439
 4440                            let doc_delimiter = maybe!({
 4441                                if !selection_is_empty {
 4442                                    return None;
 4443                                }
 4444
 4445                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4446                                    return None;
 4447                                }
 4448
 4449                                let BlockCommentConfig {
 4450                                    start: start_tag,
 4451                                    end: end_tag,
 4452                                    prefix: delimiter,
 4453                                    tab_size: len,
 4454                                } = language.documentation_comment()?;
 4455                                let is_within_block_comment = buffer
 4456                                    .language_scope_at(start_point)
 4457                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4458                                if !is_within_block_comment {
 4459                                    return None;
 4460                                }
 4461
 4462                                let (snapshot, range) =
 4463                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4464
 4465                                let num_of_whitespaces = snapshot
 4466                                    .chars_for_range(range.clone())
 4467                                    .take_while(|c| c.is_whitespace())
 4468                                    .count();
 4469
 4470                                // It is safe to use a column from MultiBufferPoint in context of a single buffer ranges, because we're only ever looking at a single line at a time.
 4471                                let column = start_point.column;
 4472                                let cursor_is_after_start_tag = {
 4473                                    let start_tag_len = start_tag.len();
 4474                                    let start_tag_line = snapshot
 4475                                        .chars_for_range(range.clone())
 4476                                        .skip(num_of_whitespaces)
 4477                                        .take(start_tag_len)
 4478                                        .collect::<String>();
 4479                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4480                                        num_of_whitespaces + start_tag_len <= column as usize
 4481                                    } else {
 4482                                        false
 4483                                    }
 4484                                };
 4485
 4486                                let cursor_is_after_delimiter = {
 4487                                    let delimiter_trim = delimiter.trim_end();
 4488                                    let delimiter_line = snapshot
 4489                                        .chars_for_range(range.clone())
 4490                                        .skip(num_of_whitespaces)
 4491                                        .take(delimiter_trim.len())
 4492                                        .collect::<String>();
 4493                                    if delimiter_line.starts_with(delimiter_trim) {
 4494                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4495                                    } else {
 4496                                        false
 4497                                    }
 4498                                };
 4499
 4500                                let cursor_is_before_end_tag_if_exists = {
 4501                                    let mut char_position = 0u32;
 4502                                    let mut end_tag_offset = None;
 4503
 4504                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4505                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4506                                            let chars_before_match =
 4507                                                chunk[..byte_pos].chars().count() as u32;
 4508                                            end_tag_offset =
 4509                                                Some(char_position + chars_before_match);
 4510                                            break 'outer;
 4511                                        }
 4512                                        char_position += chunk.chars().count() as u32;
 4513                                    }
 4514
 4515                                    if let Some(end_tag_offset) = end_tag_offset {
 4516                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4517                                        if cursor_is_after_start_tag {
 4518                                            if cursor_is_before_end_tag {
 4519                                                insert_extra_newline = true;
 4520                                            }
 4521                                            let cursor_is_at_start_of_end_tag =
 4522                                                column == end_tag_offset;
 4523                                            if cursor_is_at_start_of_end_tag {
 4524                                                indent_on_extra_newline.len = *len;
 4525                                            }
 4526                                        }
 4527                                        cursor_is_before_end_tag
 4528                                    } else {
 4529                                        true
 4530                                    }
 4531                                };
 4532
 4533                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4534                                    && cursor_is_before_end_tag_if_exists
 4535                                {
 4536                                    if cursor_is_after_start_tag {
 4537                                        indent_on_newline.len = *len;
 4538                                    }
 4539                                    Some(delimiter.clone())
 4540                                } else {
 4541                                    None
 4542                                }
 4543                            });
 4544
 4545                            (
 4546                                comment_delimiter,
 4547                                doc_delimiter,
 4548                                insert_extra_newline,
 4549                                indent_on_newline,
 4550                                indent_on_extra_newline,
 4551                            )
 4552                        } else {
 4553                            (
 4554                                None,
 4555                                None,
 4556                                false,
 4557                                IndentSize::default(),
 4558                                IndentSize::default(),
 4559                            )
 4560                        };
 4561
 4562                        let prevent_auto_indent = doc_delimiter.is_some();
 4563                        let delimiter = comment_delimiter.or(doc_delimiter);
 4564
 4565                        let capacity_for_delimiter =
 4566                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4567                        let mut new_text = String::with_capacity(
 4568                            1 + capacity_for_delimiter
 4569                                + existing_indent.len as usize
 4570                                + indent_on_newline.len as usize
 4571                                + indent_on_extra_newline.len as usize,
 4572                        );
 4573                        new_text.push('\n');
 4574                        new_text.extend(existing_indent.chars());
 4575                        new_text.extend(indent_on_newline.chars());
 4576
 4577                        if let Some(delimiter) = &delimiter {
 4578                            new_text.push_str(delimiter);
 4579                        }
 4580
 4581                        if insert_extra_newline {
 4582                            new_text.push('\n');
 4583                            new_text.extend(existing_indent.chars());
 4584                            new_text.extend(indent_on_extra_newline.chars());
 4585                        }
 4586
 4587                        let anchor = buffer.anchor_after(end);
 4588                        let new_selection = selection.map(|_| anchor);
 4589                        (
 4590                            ((start..end, new_text), prevent_auto_indent),
 4591                            (insert_extra_newline, new_selection),
 4592                        )
 4593                    })
 4594                    .unzip()
 4595            };
 4596
 4597            let mut auto_indent_edits = Vec::new();
 4598            let mut edits = Vec::new();
 4599            for (edit, prevent_auto_indent) in edits_with_flags {
 4600                if prevent_auto_indent {
 4601                    edits.push(edit);
 4602                } else {
 4603                    auto_indent_edits.push(edit);
 4604                }
 4605            }
 4606            if !edits.is_empty() {
 4607                this.edit(edits, cx);
 4608            }
 4609            if !auto_indent_edits.is_empty() {
 4610                this.edit_with_autoindent(auto_indent_edits, cx);
 4611            }
 4612
 4613            let buffer = this.buffer.read(cx).snapshot(cx);
 4614            let new_selections = selection_info
 4615                .into_iter()
 4616                .map(|(extra_newline_inserted, new_selection)| {
 4617                    let mut cursor = new_selection.end.to_point(&buffer);
 4618                    if extra_newline_inserted {
 4619                        cursor.row -= 1;
 4620                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4621                    }
 4622                    new_selection.map(|_| cursor)
 4623                })
 4624                .collect();
 4625
 4626            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4627            this.refresh_edit_prediction(true, false, window, cx);
 4628        });
 4629    }
 4630
 4631    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4632        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4633
 4634        let buffer = self.buffer.read(cx);
 4635        let snapshot = buffer.snapshot(cx);
 4636
 4637        let mut edits = Vec::new();
 4638        let mut rows = Vec::new();
 4639
 4640        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4641            let cursor = selection.head();
 4642            let row = cursor.row;
 4643
 4644            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4645
 4646            let newline = "\n".to_string();
 4647            edits.push((start_of_line..start_of_line, newline));
 4648
 4649            rows.push(row + rows_inserted as u32);
 4650        }
 4651
 4652        self.transact(window, cx, |editor, window, cx| {
 4653            editor.edit(edits, cx);
 4654
 4655            editor.change_selections(Default::default(), window, cx, |s| {
 4656                let mut index = 0;
 4657                s.move_cursors_with(|map, _, _| {
 4658                    let row = rows[index];
 4659                    index += 1;
 4660
 4661                    let point = Point::new(row, 0);
 4662                    let boundary = map.next_line_boundary(point).1;
 4663                    let clipped = map.clip_point(boundary, Bias::Left);
 4664
 4665                    (clipped, SelectionGoal::None)
 4666                });
 4667            });
 4668
 4669            let mut indent_edits = Vec::new();
 4670            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4671            for row in rows {
 4672                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4673                for (row, indent) in indents {
 4674                    if indent.len == 0 {
 4675                        continue;
 4676                    }
 4677
 4678                    let text = match indent.kind {
 4679                        IndentKind::Space => " ".repeat(indent.len as usize),
 4680                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4681                    };
 4682                    let point = Point::new(row.0, 0);
 4683                    indent_edits.push((point..point, text));
 4684                }
 4685            }
 4686            editor.edit(indent_edits, cx);
 4687        });
 4688    }
 4689
 4690    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4691        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4692
 4693        let buffer = self.buffer.read(cx);
 4694        let snapshot = buffer.snapshot(cx);
 4695
 4696        let mut edits = Vec::new();
 4697        let mut rows = Vec::new();
 4698        let mut rows_inserted = 0;
 4699
 4700        for selection in self.selections.all_adjusted(cx) {
 4701            let cursor = selection.head();
 4702            let row = cursor.row;
 4703
 4704            let point = Point::new(row + 1, 0);
 4705            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4706
 4707            let newline = "\n".to_string();
 4708            edits.push((start_of_line..start_of_line, newline));
 4709
 4710            rows_inserted += 1;
 4711            rows.push(row + rows_inserted);
 4712        }
 4713
 4714        self.transact(window, cx, |editor, window, cx| {
 4715            editor.edit(edits, cx);
 4716
 4717            editor.change_selections(Default::default(), window, cx, |s| {
 4718                let mut index = 0;
 4719                s.move_cursors_with(|map, _, _| {
 4720                    let row = rows[index];
 4721                    index += 1;
 4722
 4723                    let point = Point::new(row, 0);
 4724                    let boundary = map.next_line_boundary(point).1;
 4725                    let clipped = map.clip_point(boundary, Bias::Left);
 4726
 4727                    (clipped, SelectionGoal::None)
 4728                });
 4729            });
 4730
 4731            let mut indent_edits = Vec::new();
 4732            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4733            for row in rows {
 4734                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4735                for (row, indent) in indents {
 4736                    if indent.len == 0 {
 4737                        continue;
 4738                    }
 4739
 4740                    let text = match indent.kind {
 4741                        IndentKind::Space => " ".repeat(indent.len as usize),
 4742                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4743                    };
 4744                    let point = Point::new(row.0, 0);
 4745                    indent_edits.push((point..point, text));
 4746                }
 4747            }
 4748            editor.edit(indent_edits, cx);
 4749        });
 4750    }
 4751
 4752    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4753        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4754            original_indent_columns: Vec::new(),
 4755        });
 4756        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4757    }
 4758
 4759    fn insert_with_autoindent_mode(
 4760        &mut self,
 4761        text: &str,
 4762        autoindent_mode: Option<AutoindentMode>,
 4763        window: &mut Window,
 4764        cx: &mut Context<Self>,
 4765    ) {
 4766        if self.read_only(cx) {
 4767            return;
 4768        }
 4769
 4770        let text: Arc<str> = text.into();
 4771        self.transact(window, cx, |this, window, cx| {
 4772            let old_selections = this.selections.all_adjusted(cx);
 4773            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4774                let anchors = {
 4775                    let snapshot = buffer.read(cx);
 4776                    old_selections
 4777                        .iter()
 4778                        .map(|s| {
 4779                            let anchor = snapshot.anchor_after(s.head());
 4780                            s.map(|_| anchor)
 4781                        })
 4782                        .collect::<Vec<_>>()
 4783                };
 4784                buffer.edit(
 4785                    old_selections
 4786                        .iter()
 4787                        .map(|s| (s.start..s.end, text.clone())),
 4788                    autoindent_mode,
 4789                    cx,
 4790                );
 4791                anchors
 4792            });
 4793
 4794            this.change_selections(Default::default(), window, cx, |s| {
 4795                s.select_anchors(selection_anchors);
 4796            });
 4797
 4798            cx.notify();
 4799        });
 4800    }
 4801
 4802    fn trigger_completion_on_input(
 4803        &mut self,
 4804        text: &str,
 4805        trigger_in_words: bool,
 4806        window: &mut Window,
 4807        cx: &mut Context<Self>,
 4808    ) {
 4809        let completions_source = self
 4810            .context_menu
 4811            .borrow()
 4812            .as_ref()
 4813            .and_then(|menu| match menu {
 4814                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4815                CodeContextMenu::CodeActions(_) => None,
 4816            });
 4817
 4818        match completions_source {
 4819            Some(CompletionsMenuSource::Words) => {
 4820                self.show_word_completions(&ShowWordCompletions, window, cx)
 4821            }
 4822            Some(CompletionsMenuSource::Normal)
 4823            | Some(CompletionsMenuSource::SnippetChoices)
 4824            | None
 4825                if self.is_completion_trigger(
 4826                    text,
 4827                    trigger_in_words,
 4828                    completions_source.is_some(),
 4829                    cx,
 4830                ) =>
 4831            {
 4832                self.show_completions(
 4833                    &ShowCompletions {
 4834                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4835                    },
 4836                    window,
 4837                    cx,
 4838                )
 4839            }
 4840            _ => {
 4841                self.hide_context_menu(window, cx);
 4842            }
 4843        }
 4844    }
 4845
 4846    fn is_completion_trigger(
 4847        &self,
 4848        text: &str,
 4849        trigger_in_words: bool,
 4850        menu_is_open: bool,
 4851        cx: &mut Context<Self>,
 4852    ) -> bool {
 4853        let position = self.selections.newest_anchor().head();
 4854        let multibuffer = self.buffer.read(cx);
 4855        let Some(buffer) = position
 4856            .buffer_id
 4857            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4858        else {
 4859            return false;
 4860        };
 4861
 4862        if let Some(completion_provider) = &self.completion_provider {
 4863            completion_provider.is_completion_trigger(
 4864                &buffer,
 4865                position.text_anchor,
 4866                text,
 4867                trigger_in_words,
 4868                menu_is_open,
 4869                cx,
 4870            )
 4871        } else {
 4872            false
 4873        }
 4874    }
 4875
 4876    /// If any empty selections is touching the start of its innermost containing autoclose
 4877    /// region, expand it to select the brackets.
 4878    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4879        let selections = self.selections.all::<usize>(cx);
 4880        let buffer = self.buffer.read(cx).read(cx);
 4881        let new_selections = self
 4882            .selections_with_autoclose_regions(selections, &buffer)
 4883            .map(|(mut selection, region)| {
 4884                if !selection.is_empty() {
 4885                    return selection;
 4886                }
 4887
 4888                if let Some(region) = region {
 4889                    let mut range = region.range.to_offset(&buffer);
 4890                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4891                        range.start -= region.pair.start.len();
 4892                        if buffer.contains_str_at(range.start, &region.pair.start)
 4893                            && buffer.contains_str_at(range.end, &region.pair.end)
 4894                        {
 4895                            range.end += region.pair.end.len();
 4896                            selection.start = range.start;
 4897                            selection.end = range.end;
 4898
 4899                            return selection;
 4900                        }
 4901                    }
 4902                }
 4903
 4904                let always_treat_brackets_as_autoclosed = buffer
 4905                    .language_settings_at(selection.start, cx)
 4906                    .always_treat_brackets_as_autoclosed;
 4907
 4908                if !always_treat_brackets_as_autoclosed {
 4909                    return selection;
 4910                }
 4911
 4912                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4913                    for (pair, enabled) in scope.brackets() {
 4914                        if !enabled || !pair.close {
 4915                            continue;
 4916                        }
 4917
 4918                        if buffer.contains_str_at(selection.start, &pair.end) {
 4919                            let pair_start_len = pair.start.len();
 4920                            if buffer.contains_str_at(
 4921                                selection.start.saturating_sub(pair_start_len),
 4922                                &pair.start,
 4923                            ) {
 4924                                selection.start -= pair_start_len;
 4925                                selection.end += pair.end.len();
 4926
 4927                                return selection;
 4928                            }
 4929                        }
 4930                    }
 4931                }
 4932
 4933                selection
 4934            })
 4935            .collect();
 4936
 4937        drop(buffer);
 4938        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 4939            selections.select(new_selections)
 4940        });
 4941    }
 4942
 4943    /// Iterate the given selections, and for each one, find the smallest surrounding
 4944    /// autoclose region. This uses the ordering of the selections and the autoclose
 4945    /// regions to avoid repeated comparisons.
 4946    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4947        &'a self,
 4948        selections: impl IntoIterator<Item = Selection<D>>,
 4949        buffer: &'a MultiBufferSnapshot,
 4950    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4951        let mut i = 0;
 4952        let mut regions = self.autoclose_regions.as_slice();
 4953        selections.into_iter().map(move |selection| {
 4954            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4955
 4956            let mut enclosing = None;
 4957            while let Some(pair_state) = regions.get(i) {
 4958                if pair_state.range.end.to_offset(buffer) < range.start {
 4959                    regions = &regions[i + 1..];
 4960                    i = 0;
 4961                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4962                    break;
 4963                } else {
 4964                    if pair_state.selection_id == selection.id {
 4965                        enclosing = Some(pair_state);
 4966                    }
 4967                    i += 1;
 4968                }
 4969            }
 4970
 4971            (selection, enclosing)
 4972        })
 4973    }
 4974
 4975    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 4976    fn invalidate_autoclose_regions(
 4977        &mut self,
 4978        mut selections: &[Selection<Anchor>],
 4979        buffer: &MultiBufferSnapshot,
 4980    ) {
 4981        self.autoclose_regions.retain(|state| {
 4982            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 4983                return false;
 4984            }
 4985
 4986            let mut i = 0;
 4987            while let Some(selection) = selections.get(i) {
 4988                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4989                    selections = &selections[1..];
 4990                    continue;
 4991                }
 4992                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4993                    break;
 4994                }
 4995                if selection.id == state.selection_id {
 4996                    return true;
 4997                } else {
 4998                    i += 1;
 4999                }
 5000            }
 5001            false
 5002        });
 5003    }
 5004
 5005    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5006        let offset = position.to_offset(buffer);
 5007        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5008        if offset > word_range.start && kind == Some(CharKind::Word) {
 5009            Some(
 5010                buffer
 5011                    .text_for_range(word_range.start..offset)
 5012                    .collect::<String>(),
 5013            )
 5014        } else {
 5015            None
 5016        }
 5017    }
 5018
 5019    pub fn toggle_inline_values(
 5020        &mut self,
 5021        _: &ToggleInlineValues,
 5022        _: &mut Window,
 5023        cx: &mut Context<Self>,
 5024    ) {
 5025        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5026
 5027        self.refresh_inline_values(cx);
 5028    }
 5029
 5030    pub fn toggle_inlay_hints(
 5031        &mut self,
 5032        _: &ToggleInlayHints,
 5033        _: &mut Window,
 5034        cx: &mut Context<Self>,
 5035    ) {
 5036        self.refresh_inlay_hints(
 5037            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5038            cx,
 5039        );
 5040    }
 5041
 5042    pub fn inlay_hints_enabled(&self) -> bool {
 5043        self.inlay_hint_cache.enabled
 5044    }
 5045
 5046    pub fn inline_values_enabled(&self) -> bool {
 5047        self.inline_value_cache.enabled
 5048    }
 5049
 5050    #[cfg(any(test, feature = "test-support"))]
 5051    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5052        self.display_map
 5053            .read(cx)
 5054            .current_inlays()
 5055            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5056            .cloned()
 5057            .collect()
 5058    }
 5059
 5060    #[cfg(any(test, feature = "test-support"))]
 5061    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5062        self.display_map
 5063            .read(cx)
 5064            .current_inlays()
 5065            .cloned()
 5066            .collect()
 5067    }
 5068
 5069    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5070        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5071            return;
 5072        }
 5073
 5074        let reason_description = reason.description();
 5075        let ignore_debounce = matches!(
 5076            reason,
 5077            InlayHintRefreshReason::SettingsChange(_)
 5078                | InlayHintRefreshReason::Toggle(_)
 5079                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5080                | InlayHintRefreshReason::ModifiersChanged(_)
 5081        );
 5082        let (invalidate_cache, required_languages) = match reason {
 5083            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5084                match self.inlay_hint_cache.modifiers_override(enabled) {
 5085                    Some(enabled) => {
 5086                        if enabled {
 5087                            (InvalidationStrategy::RefreshRequested, None)
 5088                        } else {
 5089                            self.splice_inlays(
 5090                                &self
 5091                                    .visible_inlay_hints(cx)
 5092                                    .iter()
 5093                                    .map(|inlay| inlay.id)
 5094                                    .collect::<Vec<InlayId>>(),
 5095                                Vec::new(),
 5096                                cx,
 5097                            );
 5098                            return;
 5099                        }
 5100                    }
 5101                    None => return,
 5102                }
 5103            }
 5104            InlayHintRefreshReason::Toggle(enabled) => {
 5105                if self.inlay_hint_cache.toggle(enabled) {
 5106                    if enabled {
 5107                        (InvalidationStrategy::RefreshRequested, None)
 5108                    } else {
 5109                        self.splice_inlays(
 5110                            &self
 5111                                .visible_inlay_hints(cx)
 5112                                .iter()
 5113                                .map(|inlay| inlay.id)
 5114                                .collect::<Vec<InlayId>>(),
 5115                            Vec::new(),
 5116                            cx,
 5117                        );
 5118                        return;
 5119                    }
 5120                } else {
 5121                    return;
 5122                }
 5123            }
 5124            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5125                match self.inlay_hint_cache.update_settings(
 5126                    &self.buffer,
 5127                    new_settings,
 5128                    self.visible_inlay_hints(cx),
 5129                    cx,
 5130                ) {
 5131                    ControlFlow::Break(Some(InlaySplice {
 5132                        to_remove,
 5133                        to_insert,
 5134                    })) => {
 5135                        self.splice_inlays(&to_remove, to_insert, cx);
 5136                        return;
 5137                    }
 5138                    ControlFlow::Break(None) => return,
 5139                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5140                }
 5141            }
 5142            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5143                if let Some(InlaySplice {
 5144                    to_remove,
 5145                    to_insert,
 5146                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5147                {
 5148                    self.splice_inlays(&to_remove, to_insert, cx);
 5149                }
 5150                self.display_map.update(cx, |display_map, _| {
 5151                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5152                });
 5153                return;
 5154            }
 5155            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5156            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5157                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5158            }
 5159            InlayHintRefreshReason::RefreshRequested => {
 5160                (InvalidationStrategy::RefreshRequested, None)
 5161            }
 5162        };
 5163
 5164        if let Some(InlaySplice {
 5165            to_remove,
 5166            to_insert,
 5167        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5168            reason_description,
 5169            self.visible_excerpts(required_languages.as_ref(), cx),
 5170            invalidate_cache,
 5171            ignore_debounce,
 5172            cx,
 5173        ) {
 5174            self.splice_inlays(&to_remove, to_insert, cx);
 5175        }
 5176    }
 5177
 5178    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5179        self.display_map
 5180            .read(cx)
 5181            .current_inlays()
 5182            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5183            .cloned()
 5184            .collect()
 5185    }
 5186
 5187    pub fn visible_excerpts(
 5188        &self,
 5189        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5190        cx: &mut Context<Editor>,
 5191    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5192        let Some(project) = self.project.as_ref() else {
 5193            return HashMap::default();
 5194        };
 5195        let project = project.read(cx);
 5196        let multi_buffer = self.buffer().read(cx);
 5197        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5198        let multi_buffer_visible_start = self
 5199            .scroll_manager
 5200            .anchor()
 5201            .anchor
 5202            .to_point(&multi_buffer_snapshot);
 5203        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5204            multi_buffer_visible_start
 5205                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5206            Bias::Left,
 5207        );
 5208        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5209        multi_buffer_snapshot
 5210            .range_to_buffer_ranges(multi_buffer_visible_range)
 5211            .into_iter()
 5212            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5213            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5214                let buffer_file = project::File::from_dyn(buffer.file())?;
 5215                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5216                let worktree_entry = buffer_worktree
 5217                    .read(cx)
 5218                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5219                if worktree_entry.is_ignored {
 5220                    return None;
 5221                }
 5222
 5223                let language = buffer.language()?;
 5224                if let Some(restrict_to_languages) = restrict_to_languages {
 5225                    if !restrict_to_languages.contains(language) {
 5226                        return None;
 5227                    }
 5228                }
 5229                Some((
 5230                    excerpt_id,
 5231                    (
 5232                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5233                        buffer.version().clone(),
 5234                        excerpt_visible_range,
 5235                    ),
 5236                ))
 5237            })
 5238            .collect()
 5239    }
 5240
 5241    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5242        TextLayoutDetails {
 5243            text_system: window.text_system().clone(),
 5244            editor_style: self.style.clone().unwrap(),
 5245            rem_size: window.rem_size(),
 5246            scroll_anchor: self.scroll_manager.anchor(),
 5247            visible_rows: self.visible_line_count(),
 5248            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5249        }
 5250    }
 5251
 5252    pub fn splice_inlays(
 5253        &self,
 5254        to_remove: &[InlayId],
 5255        to_insert: Vec<Inlay>,
 5256        cx: &mut Context<Self>,
 5257    ) {
 5258        self.display_map.update(cx, |display_map, cx| {
 5259            display_map.splice_inlays(to_remove, to_insert, cx)
 5260        });
 5261        cx.notify();
 5262    }
 5263
 5264    fn trigger_on_type_formatting(
 5265        &self,
 5266        input: String,
 5267        window: &mut Window,
 5268        cx: &mut Context<Self>,
 5269    ) -> Option<Task<Result<()>>> {
 5270        if input.len() != 1 {
 5271            return None;
 5272        }
 5273
 5274        let project = self.project.as_ref()?;
 5275        let position = self.selections.newest_anchor().head();
 5276        let (buffer, buffer_position) = self
 5277            .buffer
 5278            .read(cx)
 5279            .text_anchor_for_position(position, cx)?;
 5280
 5281        let settings = language_settings::language_settings(
 5282            buffer
 5283                .read(cx)
 5284                .language_at(buffer_position)
 5285                .map(|l| l.name()),
 5286            buffer.read(cx).file(),
 5287            cx,
 5288        );
 5289        if !settings.use_on_type_format {
 5290            return None;
 5291        }
 5292
 5293        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5294        // hence we do LSP request & edit on host side only — add formats to host's history.
 5295        let push_to_lsp_host_history = true;
 5296        // If this is not the host, append its history with new edits.
 5297        let push_to_client_history = project.read(cx).is_via_collab();
 5298
 5299        let on_type_formatting = project.update(cx, |project, cx| {
 5300            project.on_type_format(
 5301                buffer.clone(),
 5302                buffer_position,
 5303                input,
 5304                push_to_lsp_host_history,
 5305                cx,
 5306            )
 5307        });
 5308        Some(cx.spawn_in(window, async move |editor, cx| {
 5309            if let Some(transaction) = on_type_formatting.await? {
 5310                if push_to_client_history {
 5311                    buffer
 5312                        .update(cx, |buffer, _| {
 5313                            buffer.push_transaction(transaction, Instant::now());
 5314                            buffer.finalize_last_transaction();
 5315                        })
 5316                        .ok();
 5317                }
 5318                editor.update(cx, |editor, cx| {
 5319                    editor.refresh_document_highlights(cx);
 5320                })?;
 5321            }
 5322            Ok(())
 5323        }))
 5324    }
 5325
 5326    pub fn show_word_completions(
 5327        &mut self,
 5328        _: &ShowWordCompletions,
 5329        window: &mut Window,
 5330        cx: &mut Context<Self>,
 5331    ) {
 5332        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5333    }
 5334
 5335    pub fn show_completions(
 5336        &mut self,
 5337        options: &ShowCompletions,
 5338        window: &mut Window,
 5339        cx: &mut Context<Self>,
 5340    ) {
 5341        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5342    }
 5343
 5344    fn open_or_update_completions_menu(
 5345        &mut self,
 5346        requested_source: Option<CompletionsMenuSource>,
 5347        trigger: Option<&str>,
 5348        window: &mut Window,
 5349        cx: &mut Context<Self>,
 5350    ) {
 5351        if self.pending_rename.is_some() {
 5352            return;
 5353        }
 5354
 5355        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5356
 5357        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5358        // inserted and selected. To handle that case, the start of the selection is used so that
 5359        // the menu starts with all choices.
 5360        let position = self
 5361            .selections
 5362            .newest_anchor()
 5363            .start
 5364            .bias_right(&multibuffer_snapshot);
 5365        if position.diff_base_anchor.is_some() {
 5366            return;
 5367        }
 5368        let (buffer, buffer_position) =
 5369            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5370                output
 5371            } else {
 5372                return;
 5373            };
 5374        let buffer_snapshot = buffer.read(cx).snapshot();
 5375
 5376        let query: Option<Arc<String>> =
 5377            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5378
 5379        drop(multibuffer_snapshot);
 5380
 5381        let provider = match requested_source {
 5382            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5383            Some(CompletionsMenuSource::Words) => None,
 5384            Some(CompletionsMenuSource::SnippetChoices) => {
 5385                log::error!("bug: SnippetChoices requested_source is not handled");
 5386                None
 5387            }
 5388        };
 5389
 5390        let sort_completions = provider
 5391            .as_ref()
 5392            .map_or(false, |provider| provider.sort_completions());
 5393
 5394        let filter_completions = provider
 5395            .as_ref()
 5396            .map_or(true, |provider| provider.filter_completions());
 5397
 5398        let trigger_kind = match trigger {
 5399            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5400                CompletionTriggerKind::TRIGGER_CHARACTER
 5401            }
 5402            _ => CompletionTriggerKind::INVOKED,
 5403        };
 5404        let completion_context = CompletionContext {
 5405            trigger_character: trigger.and_then(|trigger| {
 5406                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5407                    Some(String::from(trigger))
 5408                } else {
 5409                    None
 5410                }
 5411            }),
 5412            trigger_kind,
 5413        };
 5414
 5415        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5416        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5417        // involve trigger chars, so this is skipped in that case.
 5418        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5419        {
 5420            let menu_is_open = matches!(
 5421                self.context_menu.borrow().as_ref(),
 5422                Some(CodeContextMenu::Completions(_))
 5423            );
 5424            if menu_is_open {
 5425                self.hide_context_menu(window, cx);
 5426            }
 5427        }
 5428
 5429        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5430            if filter_completions {
 5431                menu.filter(query.clone(), provider.clone(), window, cx);
 5432            }
 5433            // When `is_incomplete` is false, no need to re-query completions when the current query
 5434            // is a suffix of the initial query.
 5435            if !menu.is_incomplete {
 5436                // If the new query is a suffix of the old query (typing more characters) and
 5437                // the previous result was complete, the existing completions can be filtered.
 5438                //
 5439                // Note that this is always true for snippet completions.
 5440                let query_matches = match (&menu.initial_query, &query) {
 5441                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5442                    (None, _) => true,
 5443                    _ => false,
 5444                };
 5445                if query_matches {
 5446                    let position_matches = if menu.initial_position == position {
 5447                        true
 5448                    } else {
 5449                        let snapshot = self.buffer.read(cx).read(cx);
 5450                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5451                    };
 5452                    if position_matches {
 5453                        return;
 5454                    }
 5455                }
 5456            }
 5457        };
 5458
 5459        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5460            buffer_snapshot.surrounding_word(buffer_position, false)
 5461        {
 5462            let word_to_exclude = buffer_snapshot
 5463                .text_for_range(word_range.clone())
 5464                .collect::<String>();
 5465            (
 5466                buffer_snapshot.anchor_before(word_range.start)
 5467                    ..buffer_snapshot.anchor_after(buffer_position),
 5468                Some(word_to_exclude),
 5469            )
 5470        } else {
 5471            (buffer_position..buffer_position, None)
 5472        };
 5473
 5474        let language = buffer_snapshot
 5475            .language_at(buffer_position)
 5476            .map(|language| language.name());
 5477
 5478        let completion_settings =
 5479            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5480
 5481        let show_completion_documentation = buffer_snapshot
 5482            .settings_at(buffer_position, cx)
 5483            .show_completion_documentation;
 5484
 5485        // The document can be large, so stay in reasonable bounds when searching for words,
 5486        // otherwise completion pop-up might be slow to appear.
 5487        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5488        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5489        let min_word_search = buffer_snapshot.clip_point(
 5490            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5491            Bias::Left,
 5492        );
 5493        let max_word_search = buffer_snapshot.clip_point(
 5494            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5495            Bias::Right,
 5496        );
 5497        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5498            ..buffer_snapshot.point_to_offset(max_word_search);
 5499
 5500        let skip_digits = query
 5501            .as_ref()
 5502            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5503
 5504        let (mut words, provider_responses) = match &provider {
 5505            Some(provider) => {
 5506                let provider_responses = provider.completions(
 5507                    position.excerpt_id,
 5508                    &buffer,
 5509                    buffer_position,
 5510                    completion_context,
 5511                    window,
 5512                    cx,
 5513                );
 5514
 5515                let words = match completion_settings.words {
 5516                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5517                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5518                        .background_spawn(async move {
 5519                            buffer_snapshot.words_in_range(WordsQuery {
 5520                                fuzzy_contents: None,
 5521                                range: word_search_range,
 5522                                skip_digits,
 5523                            })
 5524                        }),
 5525                };
 5526
 5527                (words, provider_responses)
 5528            }
 5529            None => (
 5530                cx.background_spawn(async move {
 5531                    buffer_snapshot.words_in_range(WordsQuery {
 5532                        fuzzy_contents: None,
 5533                        range: word_search_range,
 5534                        skip_digits,
 5535                    })
 5536                }),
 5537                Task::ready(Ok(Vec::new())),
 5538            ),
 5539        };
 5540
 5541        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5542
 5543        let id = post_inc(&mut self.next_completion_id);
 5544        let task = cx.spawn_in(window, async move |editor, cx| {
 5545            let Ok(()) = editor.update(cx, |this, _| {
 5546                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5547            }) else {
 5548                return;
 5549            };
 5550
 5551            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5552            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5553            let mut completions = Vec::new();
 5554            let mut is_incomplete = false;
 5555            if let Some(provider_responses) = provider_responses.await.log_err() {
 5556                if !provider_responses.is_empty() {
 5557                    for response in provider_responses {
 5558                        completions.extend(response.completions);
 5559                        is_incomplete = is_incomplete || response.is_incomplete;
 5560                    }
 5561                    if completion_settings.words == WordsCompletionMode::Fallback {
 5562                        words = Task::ready(BTreeMap::default());
 5563                    }
 5564                }
 5565            }
 5566
 5567            let mut words = words.await;
 5568            if let Some(word_to_exclude) = &word_to_exclude {
 5569                words.remove(word_to_exclude);
 5570            }
 5571            for lsp_completion in &completions {
 5572                words.remove(&lsp_completion.new_text);
 5573            }
 5574            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5575                replace_range: word_replace_range.clone(),
 5576                new_text: word.clone(),
 5577                label: CodeLabel::plain(word, None),
 5578                icon_path: None,
 5579                documentation: None,
 5580                source: CompletionSource::BufferWord {
 5581                    word_range,
 5582                    resolved: false,
 5583                },
 5584                insert_text_mode: Some(InsertTextMode::AS_IS),
 5585                confirm: None,
 5586            }));
 5587
 5588            let menu = if completions.is_empty() {
 5589                None
 5590            } else {
 5591                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5592                    let languages = editor
 5593                        .workspace
 5594                        .as_ref()
 5595                        .and_then(|(workspace, _)| workspace.upgrade())
 5596                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5597                    let menu = CompletionsMenu::new(
 5598                        id,
 5599                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5600                        sort_completions,
 5601                        show_completion_documentation,
 5602                        position,
 5603                        query.clone(),
 5604                        is_incomplete,
 5605                        buffer.clone(),
 5606                        completions.into(),
 5607                        snippet_sort_order,
 5608                        languages,
 5609                        language,
 5610                        cx,
 5611                    );
 5612
 5613                    let query = if filter_completions { query } else { None };
 5614                    let matches_task = if let Some(query) = query {
 5615                        menu.do_async_filtering(query, cx)
 5616                    } else {
 5617                        Task::ready(menu.unfiltered_matches())
 5618                    };
 5619                    (menu, matches_task)
 5620                }) else {
 5621                    return;
 5622                };
 5623
 5624                let matches = matches_task.await;
 5625
 5626                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5627                    // Newer menu already set, so exit.
 5628                    match editor.context_menu.borrow().as_ref() {
 5629                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5630                            if prev_menu.id > id {
 5631                                return;
 5632                            }
 5633                        }
 5634                        _ => {}
 5635                    };
 5636
 5637                    // Only valid to take prev_menu because it the new menu is immediately set
 5638                    // below, or the menu is hidden.
 5639                    match editor.context_menu.borrow_mut().take() {
 5640                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5641                            let position_matches =
 5642                                if prev_menu.initial_position == menu.initial_position {
 5643                                    true
 5644                                } else {
 5645                                    let snapshot = editor.buffer.read(cx).read(cx);
 5646                                    prev_menu.initial_position.to_offset(&snapshot)
 5647                                        == menu.initial_position.to_offset(&snapshot)
 5648                                };
 5649                            if position_matches {
 5650                                // Preserve markdown cache before `set_filter_results` because it will
 5651                                // try to populate the documentation cache.
 5652                                menu.preserve_markdown_cache(prev_menu);
 5653                            }
 5654                        }
 5655                        _ => {}
 5656                    };
 5657
 5658                    menu.set_filter_results(matches, provider, window, cx);
 5659                }) else {
 5660                    return;
 5661                };
 5662
 5663                menu.visible().then_some(menu)
 5664            };
 5665
 5666            editor
 5667                .update_in(cx, |editor, window, cx| {
 5668                    if editor.focus_handle.is_focused(window) {
 5669                        if let Some(menu) = menu {
 5670                            *editor.context_menu.borrow_mut() =
 5671                                Some(CodeContextMenu::Completions(menu));
 5672
 5673                            crate::hover_popover::hide_hover(editor, cx);
 5674                            if editor.show_edit_predictions_in_menu() {
 5675                                editor.update_visible_edit_prediction(window, cx);
 5676                            } else {
 5677                                editor.discard_edit_prediction(false, cx);
 5678                            }
 5679
 5680                            cx.notify();
 5681                            return;
 5682                        }
 5683                    }
 5684
 5685                    if editor.completion_tasks.len() <= 1 {
 5686                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5687                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5688                        // If it was already hidden and we don't show edit predictions in the menu,
 5689                        // we should also show the edit prediction when available.
 5690                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5691                            editor.update_visible_edit_prediction(window, cx);
 5692                        }
 5693                    }
 5694                })
 5695                .ok();
 5696        });
 5697
 5698        self.completion_tasks.push((id, task));
 5699    }
 5700
 5701    #[cfg(feature = "test-support")]
 5702    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5703        let menu = self.context_menu.borrow();
 5704        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5705            let completions = menu.completions.borrow();
 5706            Some(completions.to_vec())
 5707        } else {
 5708            None
 5709        }
 5710    }
 5711
 5712    pub fn with_completions_menu_matching_id<R>(
 5713        &self,
 5714        id: CompletionId,
 5715        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5716    ) -> R {
 5717        let mut context_menu = self.context_menu.borrow_mut();
 5718        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5719            return f(None);
 5720        };
 5721        if completions_menu.id != id {
 5722            return f(None);
 5723        }
 5724        f(Some(completions_menu))
 5725    }
 5726
 5727    pub fn confirm_completion(
 5728        &mut self,
 5729        action: &ConfirmCompletion,
 5730        window: &mut Window,
 5731        cx: &mut Context<Self>,
 5732    ) -> Option<Task<Result<()>>> {
 5733        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5734        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5735    }
 5736
 5737    pub fn confirm_completion_insert(
 5738        &mut self,
 5739        _: &ConfirmCompletionInsert,
 5740        window: &mut Window,
 5741        cx: &mut Context<Self>,
 5742    ) -> Option<Task<Result<()>>> {
 5743        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5744        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5745    }
 5746
 5747    pub fn confirm_completion_replace(
 5748        &mut self,
 5749        _: &ConfirmCompletionReplace,
 5750        window: &mut Window,
 5751        cx: &mut Context<Self>,
 5752    ) -> Option<Task<Result<()>>> {
 5753        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5754        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5755    }
 5756
 5757    pub fn compose_completion(
 5758        &mut self,
 5759        action: &ComposeCompletion,
 5760        window: &mut Window,
 5761        cx: &mut Context<Self>,
 5762    ) -> Option<Task<Result<()>>> {
 5763        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5764        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5765    }
 5766
 5767    fn do_completion(
 5768        &mut self,
 5769        item_ix: Option<usize>,
 5770        intent: CompletionIntent,
 5771        window: &mut Window,
 5772        cx: &mut Context<Editor>,
 5773    ) -> Option<Task<Result<()>>> {
 5774        use language::ToOffset as _;
 5775
 5776        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5777        else {
 5778            return None;
 5779        };
 5780
 5781        let candidate_id = {
 5782            let entries = completions_menu.entries.borrow();
 5783            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5784            if self.show_edit_predictions_in_menu() {
 5785                self.discard_edit_prediction(true, cx);
 5786            }
 5787            mat.candidate_id
 5788        };
 5789
 5790        let completion = completions_menu
 5791            .completions
 5792            .borrow()
 5793            .get(candidate_id)?
 5794            .clone();
 5795        cx.stop_propagation();
 5796
 5797        let buffer_handle = completions_menu.buffer.clone();
 5798
 5799        let CompletionEdit {
 5800            new_text,
 5801            snippet,
 5802            replace_range,
 5803        } = process_completion_for_edit(
 5804            &completion,
 5805            intent,
 5806            &buffer_handle,
 5807            &completions_menu.initial_position.text_anchor,
 5808            cx,
 5809        );
 5810
 5811        let buffer = buffer_handle.read(cx);
 5812        let snapshot = self.buffer.read(cx).snapshot(cx);
 5813        let newest_anchor = self.selections.newest_anchor();
 5814        let replace_range_multibuffer = {
 5815            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5816            let multibuffer_anchor = snapshot
 5817                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5818                .unwrap()
 5819                ..snapshot
 5820                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5821                    .unwrap();
 5822            multibuffer_anchor.start.to_offset(&snapshot)
 5823                ..multibuffer_anchor.end.to_offset(&snapshot)
 5824        };
 5825        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5826            return None;
 5827        }
 5828
 5829        let old_text = buffer
 5830            .text_for_range(replace_range.clone())
 5831            .collect::<String>();
 5832        let lookbehind = newest_anchor
 5833            .start
 5834            .text_anchor
 5835            .to_offset(buffer)
 5836            .saturating_sub(replace_range.start);
 5837        let lookahead = replace_range
 5838            .end
 5839            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5840        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5841        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5842
 5843        let selections = self.selections.all::<usize>(cx);
 5844        let mut ranges = Vec::new();
 5845        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5846
 5847        for selection in &selections {
 5848            let range = if selection.id == newest_anchor.id {
 5849                replace_range_multibuffer.clone()
 5850            } else {
 5851                let mut range = selection.range();
 5852
 5853                // if prefix is present, don't duplicate it
 5854                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5855                    range.start = range.start.saturating_sub(lookbehind);
 5856
 5857                    // if suffix is also present, mimic the newest cursor and replace it
 5858                    if selection.id != newest_anchor.id
 5859                        && snapshot.contains_str_at(range.end, suffix)
 5860                    {
 5861                        range.end += lookahead;
 5862                    }
 5863                }
 5864                range
 5865            };
 5866
 5867            ranges.push(range.clone());
 5868
 5869            if !self.linked_edit_ranges.is_empty() {
 5870                let start_anchor = snapshot.anchor_before(range.start);
 5871                let end_anchor = snapshot.anchor_after(range.end);
 5872                if let Some(ranges) = self
 5873                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5874                {
 5875                    for (buffer, edits) in ranges {
 5876                        linked_edits
 5877                            .entry(buffer.clone())
 5878                            .or_default()
 5879                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5880                    }
 5881                }
 5882            }
 5883        }
 5884
 5885        let common_prefix_len = old_text
 5886            .chars()
 5887            .zip(new_text.chars())
 5888            .take_while(|(a, b)| a == b)
 5889            .map(|(a, _)| a.len_utf8())
 5890            .sum::<usize>();
 5891
 5892        cx.emit(EditorEvent::InputHandled {
 5893            utf16_range_to_replace: None,
 5894            text: new_text[common_prefix_len..].into(),
 5895        });
 5896
 5897        self.transact(window, cx, |editor, window, cx| {
 5898            if let Some(mut snippet) = snippet {
 5899                snippet.text = new_text.to_string();
 5900                editor
 5901                    .insert_snippet(&ranges, snippet, window, cx)
 5902                    .log_err();
 5903            } else {
 5904                editor.buffer.update(cx, |multi_buffer, cx| {
 5905                    let auto_indent = match completion.insert_text_mode {
 5906                        Some(InsertTextMode::AS_IS) => None,
 5907                        _ => editor.autoindent_mode.clone(),
 5908                    };
 5909                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5910                    multi_buffer.edit(edits, auto_indent, cx);
 5911                });
 5912            }
 5913            for (buffer, edits) in linked_edits {
 5914                buffer.update(cx, |buffer, cx| {
 5915                    let snapshot = buffer.snapshot();
 5916                    let edits = edits
 5917                        .into_iter()
 5918                        .map(|(range, text)| {
 5919                            use text::ToPoint as TP;
 5920                            let end_point = TP::to_point(&range.end, &snapshot);
 5921                            let start_point = TP::to_point(&range.start, &snapshot);
 5922                            (start_point..end_point, text)
 5923                        })
 5924                        .sorted_by_key(|(range, _)| range.start);
 5925                    buffer.edit(edits, None, cx);
 5926                })
 5927            }
 5928
 5929            editor.refresh_edit_prediction(true, false, window, cx);
 5930        });
 5931        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), &snapshot);
 5932
 5933        let show_new_completions_on_confirm = completion
 5934            .confirm
 5935            .as_ref()
 5936            .map_or(false, |confirm| confirm(intent, window, cx));
 5937        if show_new_completions_on_confirm {
 5938            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5939        }
 5940
 5941        let provider = self.completion_provider.as_ref()?;
 5942        drop(completion);
 5943        let apply_edits = provider.apply_additional_edits_for_completion(
 5944            buffer_handle,
 5945            completions_menu.completions.clone(),
 5946            candidate_id,
 5947            true,
 5948            cx,
 5949        );
 5950
 5951        let editor_settings = EditorSettings::get_global(cx);
 5952        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5953            // After the code completion is finished, users often want to know what signatures are needed.
 5954            // so we should automatically call signature_help
 5955            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5956        }
 5957
 5958        Some(cx.foreground_executor().spawn(async move {
 5959            apply_edits.await?;
 5960            Ok(())
 5961        }))
 5962    }
 5963
 5964    pub fn toggle_code_actions(
 5965        &mut self,
 5966        action: &ToggleCodeActions,
 5967        window: &mut Window,
 5968        cx: &mut Context<Self>,
 5969    ) {
 5970        let quick_launch = action.quick_launch;
 5971        let mut context_menu = self.context_menu.borrow_mut();
 5972        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5973            if code_actions.deployed_from == action.deployed_from {
 5974                // Toggle if we're selecting the same one
 5975                *context_menu = None;
 5976                cx.notify();
 5977                return;
 5978            } else {
 5979                // Otherwise, clear it and start a new one
 5980                *context_menu = None;
 5981                cx.notify();
 5982            }
 5983        }
 5984        drop(context_menu);
 5985        let snapshot = self.snapshot(window, cx);
 5986        let deployed_from = action.deployed_from.clone();
 5987        let action = action.clone();
 5988        self.completion_tasks.clear();
 5989        self.discard_edit_prediction(false, cx);
 5990
 5991        let multibuffer_point = match &action.deployed_from {
 5992            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5993                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5994            }
 5995            _ => self.selections.newest::<Point>(cx).head(),
 5996        };
 5997        let Some((buffer, buffer_row)) = snapshot
 5998            .buffer_snapshot
 5999            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6000            .and_then(|(buffer_snapshot, range)| {
 6001                self.buffer()
 6002                    .read(cx)
 6003                    .buffer(buffer_snapshot.remote_id())
 6004                    .map(|buffer| (buffer, range.start.row))
 6005            })
 6006        else {
 6007            return;
 6008        };
 6009        let buffer_id = buffer.read(cx).remote_id();
 6010        let tasks = self
 6011            .tasks
 6012            .get(&(buffer_id, buffer_row))
 6013            .map(|t| Arc::new(t.to_owned()));
 6014
 6015        if !self.focus_handle.is_focused(window) {
 6016            return;
 6017        }
 6018        let project = self.project.clone();
 6019
 6020        let code_actions_task = match deployed_from {
 6021            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6022            _ => self.code_actions(buffer_row, window, cx),
 6023        };
 6024
 6025        let runnable_task = match deployed_from {
 6026            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6027            _ => {
 6028                let mut task_context_task = Task::ready(None);
 6029                if let Some(tasks) = &tasks {
 6030                    if let Some(project) = project {
 6031                        task_context_task =
 6032                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 6033                    }
 6034                }
 6035
 6036                cx.spawn_in(window, {
 6037                    let buffer = buffer.clone();
 6038                    async move |editor, cx| {
 6039                        let task_context = task_context_task.await;
 6040
 6041                        let resolved_tasks =
 6042                            tasks
 6043                                .zip(task_context.clone())
 6044                                .map(|(tasks, task_context)| ResolvedTasks {
 6045                                    templates: tasks.resolve(&task_context).collect(),
 6046                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6047                                        multibuffer_point.row,
 6048                                        tasks.column,
 6049                                    )),
 6050                                });
 6051                        let debug_scenarios = editor
 6052                            .update(cx, |editor, cx| {
 6053                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6054                            })?
 6055                            .await;
 6056                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6057                    }
 6058                })
 6059            }
 6060        };
 6061
 6062        cx.spawn_in(window, async move |editor, cx| {
 6063            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6064            let code_actions = code_actions_task.await;
 6065            let spawn_straight_away = quick_launch
 6066                && resolved_tasks
 6067                    .as_ref()
 6068                    .map_or(false, |tasks| tasks.templates.len() == 1)
 6069                && code_actions
 6070                    .as_ref()
 6071                    .map_or(true, |actions| actions.is_empty())
 6072                && debug_scenarios.is_empty();
 6073
 6074            editor.update_in(cx, |editor, window, cx| {
 6075                crate::hover_popover::hide_hover(editor, cx);
 6076                let actions = CodeActionContents::new(
 6077                    resolved_tasks,
 6078                    code_actions,
 6079                    debug_scenarios,
 6080                    task_context.unwrap_or_default(),
 6081                );
 6082
 6083                // Don't show the menu if there are no actions available
 6084                if actions.is_empty() {
 6085                    cx.notify();
 6086                    return Task::ready(Ok(()));
 6087                }
 6088
 6089                *editor.context_menu.borrow_mut() =
 6090                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6091                        buffer,
 6092                        actions,
 6093                        selected_item: Default::default(),
 6094                        scroll_handle: UniformListScrollHandle::default(),
 6095                        deployed_from,
 6096                    }));
 6097                cx.notify();
 6098                if spawn_straight_away {
 6099                    if let Some(task) = editor.confirm_code_action(
 6100                        &ConfirmCodeAction { item_ix: Some(0) },
 6101                        window,
 6102                        cx,
 6103                    ) {
 6104                        return task;
 6105                    }
 6106                }
 6107
 6108                Task::ready(Ok(()))
 6109            })
 6110        })
 6111        .detach_and_log_err(cx);
 6112    }
 6113
 6114    fn debug_scenarios(
 6115        &mut self,
 6116        resolved_tasks: &Option<ResolvedTasks>,
 6117        buffer: &Entity<Buffer>,
 6118        cx: &mut App,
 6119    ) -> Task<Vec<task::DebugScenario>> {
 6120        maybe!({
 6121            let project = self.project.as_ref()?;
 6122            let dap_store = project.read(cx).dap_store();
 6123            let mut scenarios = vec![];
 6124            let resolved_tasks = resolved_tasks.as_ref()?;
 6125            let buffer = buffer.read(cx);
 6126            let language = buffer.language()?;
 6127            let file = buffer.file();
 6128            let debug_adapter = language_settings(language.name().into(), file, cx)
 6129                .debuggers
 6130                .first()
 6131                .map(SharedString::from)
 6132                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6133
 6134            dap_store.update(cx, |dap_store, cx| {
 6135                for (_, task) in &resolved_tasks.templates {
 6136                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6137                        task.original_task().clone(),
 6138                        debug_adapter.clone().into(),
 6139                        task.display_label().to_owned().into(),
 6140                        cx,
 6141                    );
 6142                    scenarios.push(maybe_scenario);
 6143                }
 6144            });
 6145            Some(cx.background_spawn(async move {
 6146                let scenarios = futures::future::join_all(scenarios)
 6147                    .await
 6148                    .into_iter()
 6149                    .flatten()
 6150                    .collect::<Vec<_>>();
 6151                scenarios
 6152            }))
 6153        })
 6154        .unwrap_or_else(|| Task::ready(vec![]))
 6155    }
 6156
 6157    fn code_actions(
 6158        &mut self,
 6159        buffer_row: u32,
 6160        window: &mut Window,
 6161        cx: &mut Context<Self>,
 6162    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6163        let mut task = self.code_actions_task.take();
 6164        cx.spawn_in(window, async move |editor, cx| {
 6165            while let Some(prev_task) = task {
 6166                prev_task.await.log_err();
 6167                task = editor
 6168                    .update(cx, |this, _| this.code_actions_task.take())
 6169                    .ok()?;
 6170            }
 6171
 6172            editor
 6173                .update(cx, |editor, cx| {
 6174                    editor
 6175                        .available_code_actions
 6176                        .clone()
 6177                        .and_then(|(location, code_actions)| {
 6178                            let snapshot = location.buffer.read(cx).snapshot();
 6179                            let point_range = location.range.to_point(&snapshot);
 6180                            let point_range = point_range.start.row..=point_range.end.row;
 6181                            if point_range.contains(&buffer_row) {
 6182                                Some(code_actions)
 6183                            } else {
 6184                                None
 6185                            }
 6186                        })
 6187                })
 6188                .ok()
 6189                .flatten()
 6190        })
 6191    }
 6192
 6193    pub fn confirm_code_action(
 6194        &mut self,
 6195        action: &ConfirmCodeAction,
 6196        window: &mut Window,
 6197        cx: &mut Context<Self>,
 6198    ) -> Option<Task<Result<()>>> {
 6199        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6200
 6201        let actions_menu =
 6202            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6203                menu
 6204            } else {
 6205                return None;
 6206            };
 6207
 6208        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6209        let action = actions_menu.actions.get(action_ix)?;
 6210        let title = action.label();
 6211        let buffer = actions_menu.buffer;
 6212        let workspace = self.workspace()?;
 6213
 6214        match action {
 6215            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6216                workspace.update(cx, |workspace, cx| {
 6217                    workspace.schedule_resolved_task(
 6218                        task_source_kind,
 6219                        resolved_task,
 6220                        false,
 6221                        window,
 6222                        cx,
 6223                    );
 6224
 6225                    Some(Task::ready(Ok(())))
 6226                })
 6227            }
 6228            CodeActionsItem::CodeAction {
 6229                excerpt_id,
 6230                action,
 6231                provider,
 6232            } => {
 6233                let apply_code_action =
 6234                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6235                let workspace = workspace.downgrade();
 6236                Some(cx.spawn_in(window, async move |editor, cx| {
 6237                    let project_transaction = apply_code_action.await?;
 6238                    Self::open_project_transaction(
 6239                        &editor,
 6240                        workspace,
 6241                        project_transaction,
 6242                        title,
 6243                        cx,
 6244                    )
 6245                    .await
 6246                }))
 6247            }
 6248            CodeActionsItem::DebugScenario(scenario) => {
 6249                let context = actions_menu.actions.context.clone();
 6250
 6251                workspace.update(cx, |workspace, cx| {
 6252                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6253                    workspace.start_debug_session(
 6254                        scenario,
 6255                        context,
 6256                        Some(buffer),
 6257                        None,
 6258                        window,
 6259                        cx,
 6260                    );
 6261                });
 6262                Some(Task::ready(Ok(())))
 6263            }
 6264        }
 6265    }
 6266
 6267    pub async fn open_project_transaction(
 6268        this: &WeakEntity<Editor>,
 6269        workspace: WeakEntity<Workspace>,
 6270        transaction: ProjectTransaction,
 6271        title: String,
 6272        cx: &mut AsyncWindowContext,
 6273    ) -> Result<()> {
 6274        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6275        cx.update(|_, cx| {
 6276            entries.sort_unstable_by_key(|(buffer, _)| {
 6277                buffer.read(cx).file().map(|f| f.path().clone())
 6278            });
 6279        })?;
 6280
 6281        // If the project transaction's edits are all contained within this editor, then
 6282        // avoid opening a new editor to display them.
 6283
 6284        if let Some((buffer, transaction)) = entries.first() {
 6285            if entries.len() == 1 {
 6286                let excerpt = this.update(cx, |editor, cx| {
 6287                    editor
 6288                        .buffer()
 6289                        .read(cx)
 6290                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6291                })?;
 6292                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6293                    if excerpted_buffer == *buffer {
 6294                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6295                            let excerpt_range = excerpt_range.to_offset(buffer);
 6296                            buffer
 6297                                .edited_ranges_for_transaction::<usize>(transaction)
 6298                                .all(|range| {
 6299                                    excerpt_range.start <= range.start
 6300                                        && excerpt_range.end >= range.end
 6301                                })
 6302                        })?;
 6303
 6304                        if all_edits_within_excerpt {
 6305                            return Ok(());
 6306                        }
 6307                    }
 6308                }
 6309            }
 6310        } else {
 6311            return Ok(());
 6312        }
 6313
 6314        let mut ranges_to_highlight = Vec::new();
 6315        let excerpt_buffer = cx.new(|cx| {
 6316            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6317            for (buffer_handle, transaction) in &entries {
 6318                let edited_ranges = buffer_handle
 6319                    .read(cx)
 6320                    .edited_ranges_for_transaction::<Point>(transaction)
 6321                    .collect::<Vec<_>>();
 6322                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6323                    PathKey::for_buffer(buffer_handle, cx),
 6324                    buffer_handle.clone(),
 6325                    edited_ranges,
 6326                    DEFAULT_MULTIBUFFER_CONTEXT,
 6327                    cx,
 6328                );
 6329
 6330                ranges_to_highlight.extend(ranges);
 6331            }
 6332            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6333            multibuffer
 6334        })?;
 6335
 6336        workspace.update_in(cx, |workspace, window, cx| {
 6337            let project = workspace.project().clone();
 6338            let editor =
 6339                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6340            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6341            editor.update(cx, |editor, cx| {
 6342                editor.highlight_background::<Self>(
 6343                    &ranges_to_highlight,
 6344                    |theme| theme.colors().editor_highlighted_line_background,
 6345                    cx,
 6346                );
 6347            });
 6348        })?;
 6349
 6350        Ok(())
 6351    }
 6352
 6353    pub fn clear_code_action_providers(&mut self) {
 6354        self.code_action_providers.clear();
 6355        self.available_code_actions.take();
 6356    }
 6357
 6358    pub fn add_code_action_provider(
 6359        &mut self,
 6360        provider: Rc<dyn CodeActionProvider>,
 6361        window: &mut Window,
 6362        cx: &mut Context<Self>,
 6363    ) {
 6364        if self
 6365            .code_action_providers
 6366            .iter()
 6367            .any(|existing_provider| existing_provider.id() == provider.id())
 6368        {
 6369            return;
 6370        }
 6371
 6372        self.code_action_providers.push(provider);
 6373        self.refresh_code_actions(window, cx);
 6374    }
 6375
 6376    pub fn remove_code_action_provider(
 6377        &mut self,
 6378        id: Arc<str>,
 6379        window: &mut Window,
 6380        cx: &mut Context<Self>,
 6381    ) {
 6382        self.code_action_providers
 6383            .retain(|provider| provider.id() != id);
 6384        self.refresh_code_actions(window, cx);
 6385    }
 6386
 6387    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6388        !self.code_action_providers.is_empty()
 6389            && EditorSettings::get_global(cx).toolbar.code_actions
 6390    }
 6391
 6392    pub fn has_available_code_actions(&self) -> bool {
 6393        self.available_code_actions
 6394            .as_ref()
 6395            .is_some_and(|(_, actions)| !actions.is_empty())
 6396    }
 6397
 6398    fn render_inline_code_actions(
 6399        &self,
 6400        icon_size: ui::IconSize,
 6401        display_row: DisplayRow,
 6402        is_active: bool,
 6403        cx: &mut Context<Self>,
 6404    ) -> AnyElement {
 6405        let show_tooltip = !self.context_menu_visible();
 6406        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6407            .icon_size(icon_size)
 6408            .shape(ui::IconButtonShape::Square)
 6409            .icon_color(ui::Color::Hidden)
 6410            .toggle_state(is_active)
 6411            .when(show_tooltip, |this| {
 6412                this.tooltip({
 6413                    let focus_handle = self.focus_handle.clone();
 6414                    move |window, cx| {
 6415                        Tooltip::for_action_in(
 6416                            "Toggle Code Actions",
 6417                            &ToggleCodeActions {
 6418                                deployed_from: None,
 6419                                quick_launch: false,
 6420                            },
 6421                            &focus_handle,
 6422                            window,
 6423                            cx,
 6424                        )
 6425                    }
 6426                })
 6427            })
 6428            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6429                window.focus(&editor.focus_handle(cx));
 6430                editor.toggle_code_actions(
 6431                    &crate::actions::ToggleCodeActions {
 6432                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6433                            display_row,
 6434                        )),
 6435                        quick_launch: false,
 6436                    },
 6437                    window,
 6438                    cx,
 6439                );
 6440            }))
 6441            .into_any_element()
 6442    }
 6443
 6444    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6445        &self.context_menu
 6446    }
 6447
 6448    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6449        let newest_selection = self.selections.newest_anchor().clone();
 6450        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6451        let buffer = self.buffer.read(cx);
 6452        if newest_selection.head().diff_base_anchor.is_some() {
 6453            return None;
 6454        }
 6455        let (start_buffer, start) =
 6456            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6457        let (end_buffer, end) =
 6458            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6459        if start_buffer != end_buffer {
 6460            return None;
 6461        }
 6462
 6463        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6464            cx.background_executor()
 6465                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6466                .await;
 6467
 6468            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6469                let providers = this.code_action_providers.clone();
 6470                let tasks = this
 6471                    .code_action_providers
 6472                    .iter()
 6473                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6474                    .collect::<Vec<_>>();
 6475                (providers, tasks)
 6476            })?;
 6477
 6478            let mut actions = Vec::new();
 6479            for (provider, provider_actions) in
 6480                providers.into_iter().zip(future::join_all(tasks).await)
 6481            {
 6482                if let Some(provider_actions) = provider_actions.log_err() {
 6483                    actions.extend(provider_actions.into_iter().map(|action| {
 6484                        AvailableCodeAction {
 6485                            excerpt_id: newest_selection.start.excerpt_id,
 6486                            action,
 6487                            provider: provider.clone(),
 6488                        }
 6489                    }));
 6490                }
 6491            }
 6492
 6493            this.update(cx, |this, cx| {
 6494                this.available_code_actions = if actions.is_empty() {
 6495                    None
 6496                } else {
 6497                    Some((
 6498                        Location {
 6499                            buffer: start_buffer,
 6500                            range: start..end,
 6501                        },
 6502                        actions.into(),
 6503                    ))
 6504                };
 6505                cx.notify();
 6506            })
 6507        }));
 6508        None
 6509    }
 6510
 6511    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6512        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6513            self.show_git_blame_inline = false;
 6514
 6515            self.show_git_blame_inline_delay_task =
 6516                Some(cx.spawn_in(window, async move |this, cx| {
 6517                    cx.background_executor().timer(delay).await;
 6518
 6519                    this.update(cx, |this, cx| {
 6520                        this.show_git_blame_inline = true;
 6521                        cx.notify();
 6522                    })
 6523                    .log_err();
 6524                }));
 6525        }
 6526    }
 6527
 6528    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6529        let snapshot = self.snapshot(window, cx);
 6530        let cursor = self.selections.newest::<Point>(cx).head();
 6531        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6532        else {
 6533            return;
 6534        };
 6535
 6536        let Some(blame) = self.blame.as_ref() else {
 6537            return;
 6538        };
 6539
 6540        let row_info = RowInfo {
 6541            buffer_id: Some(buffer.remote_id()),
 6542            buffer_row: Some(point.row),
 6543            ..Default::default()
 6544        };
 6545        let Some(blame_entry) = blame
 6546            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6547            .flatten()
 6548        else {
 6549            return;
 6550        };
 6551
 6552        let anchor = self.selections.newest_anchor().head();
 6553        let position = self.to_pixel_point(anchor, &snapshot, window);
 6554        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6555            self.show_blame_popover(&blame_entry, position + last_bounds.origin, true, cx);
 6556        };
 6557    }
 6558
 6559    fn show_blame_popover(
 6560        &mut self,
 6561        blame_entry: &BlameEntry,
 6562        position: gpui::Point<Pixels>,
 6563        ignore_timeout: bool,
 6564        cx: &mut Context<Self>,
 6565    ) {
 6566        if let Some(state) = &mut self.inline_blame_popover {
 6567            state.hide_task.take();
 6568        } else {
 6569            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6570            let blame_entry = blame_entry.clone();
 6571            let show_task = cx.spawn(async move |editor, cx| {
 6572                if !ignore_timeout {
 6573                    cx.background_executor()
 6574                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6575                        .await;
 6576                }
 6577                editor
 6578                    .update(cx, |editor, cx| {
 6579                        editor.inline_blame_popover_show_task.take();
 6580                        let Some(blame) = editor.blame.as_ref() else {
 6581                            return;
 6582                        };
 6583                        let blame = blame.read(cx);
 6584                        let details = blame.details_for_entry(&blame_entry);
 6585                        let markdown = cx.new(|cx| {
 6586                            Markdown::new(
 6587                                details
 6588                                    .as_ref()
 6589                                    .map(|message| message.message.clone())
 6590                                    .unwrap_or_default(),
 6591                                None,
 6592                                None,
 6593                                cx,
 6594                            )
 6595                        });
 6596                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6597                            position,
 6598                            hide_task: None,
 6599                            popover_bounds: None,
 6600                            popover_state: InlineBlamePopoverState {
 6601                                scroll_handle: ScrollHandle::new(),
 6602                                commit_message: details,
 6603                                markdown,
 6604                            },
 6605                            keyboard_grace: ignore_timeout,
 6606                        });
 6607                        cx.notify();
 6608                    })
 6609                    .ok();
 6610            });
 6611            self.inline_blame_popover_show_task = Some(show_task);
 6612        }
 6613    }
 6614
 6615    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6616        self.inline_blame_popover_show_task.take();
 6617        if let Some(state) = &mut self.inline_blame_popover {
 6618            let hide_task = cx.spawn(async move |editor, cx| {
 6619                cx.background_executor()
 6620                    .timer(std::time::Duration::from_millis(100))
 6621                    .await;
 6622                editor
 6623                    .update(cx, |editor, cx| {
 6624                        editor.inline_blame_popover.take();
 6625                        cx.notify();
 6626                    })
 6627                    .ok();
 6628            });
 6629            state.hide_task = Some(hide_task);
 6630        }
 6631    }
 6632
 6633    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6634        if self.pending_rename.is_some() {
 6635            return None;
 6636        }
 6637
 6638        let provider = self.semantics_provider.clone()?;
 6639        let buffer = self.buffer.read(cx);
 6640        let newest_selection = self.selections.newest_anchor().clone();
 6641        let cursor_position = newest_selection.head();
 6642        let (cursor_buffer, cursor_buffer_position) =
 6643            buffer.text_anchor_for_position(cursor_position, cx)?;
 6644        let (tail_buffer, tail_buffer_position) =
 6645            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6646        if cursor_buffer != tail_buffer {
 6647            return None;
 6648        }
 6649
 6650        let snapshot = cursor_buffer.read(cx).snapshot();
 6651        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6652        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6653        if start_word_range != end_word_range {
 6654            self.document_highlights_task.take();
 6655            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6656            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6657            return None;
 6658        }
 6659
 6660        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6661        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6662            cx.background_executor()
 6663                .timer(Duration::from_millis(debounce))
 6664                .await;
 6665
 6666            let highlights = if let Some(highlights) = cx
 6667                .update(|cx| {
 6668                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6669                })
 6670                .ok()
 6671                .flatten()
 6672            {
 6673                highlights.await.log_err()
 6674            } else {
 6675                None
 6676            };
 6677
 6678            if let Some(highlights) = highlights {
 6679                this.update(cx, |this, cx| {
 6680                    if this.pending_rename.is_some() {
 6681                        return;
 6682                    }
 6683
 6684                    let buffer_id = cursor_position.buffer_id;
 6685                    let buffer = this.buffer.read(cx);
 6686                    if !buffer
 6687                        .text_anchor_for_position(cursor_position, cx)
 6688                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6689                    {
 6690                        return;
 6691                    }
 6692
 6693                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6694                    let mut write_ranges = Vec::new();
 6695                    let mut read_ranges = Vec::new();
 6696                    for highlight in highlights {
 6697                        for (excerpt_id, excerpt_range) in
 6698                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6699                        {
 6700                            let start = highlight
 6701                                .range
 6702                                .start
 6703                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6704                            let end = highlight
 6705                                .range
 6706                                .end
 6707                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6708                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6709                                continue;
 6710                            }
 6711
 6712                            let range = Anchor {
 6713                                buffer_id,
 6714                                excerpt_id,
 6715                                text_anchor: start,
 6716                                diff_base_anchor: None,
 6717                            }..Anchor {
 6718                                buffer_id,
 6719                                excerpt_id,
 6720                                text_anchor: end,
 6721                                diff_base_anchor: None,
 6722                            };
 6723                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6724                                write_ranges.push(range);
 6725                            } else {
 6726                                read_ranges.push(range);
 6727                            }
 6728                        }
 6729                    }
 6730
 6731                    this.highlight_background::<DocumentHighlightRead>(
 6732                        &read_ranges,
 6733                        |theme| theme.colors().editor_document_highlight_read_background,
 6734                        cx,
 6735                    );
 6736                    this.highlight_background::<DocumentHighlightWrite>(
 6737                        &write_ranges,
 6738                        |theme| theme.colors().editor_document_highlight_write_background,
 6739                        cx,
 6740                    );
 6741                    cx.notify();
 6742                })
 6743                .log_err();
 6744            }
 6745        }));
 6746        None
 6747    }
 6748
 6749    fn prepare_highlight_query_from_selection(
 6750        &mut self,
 6751        cx: &mut Context<Editor>,
 6752    ) -> Option<(String, Range<Anchor>)> {
 6753        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6754            return None;
 6755        }
 6756        if !EditorSettings::get_global(cx).selection_highlight {
 6757            return None;
 6758        }
 6759        if self.selections.count() != 1 || self.selections.line_mode {
 6760            return None;
 6761        }
 6762        let selection = self.selections.newest::<Point>(cx);
 6763        if selection.is_empty() || selection.start.row != selection.end.row {
 6764            return None;
 6765        }
 6766        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6767        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6768        let query = multi_buffer_snapshot
 6769            .text_for_range(selection_anchor_range.clone())
 6770            .collect::<String>();
 6771        if query.trim().is_empty() {
 6772            return None;
 6773        }
 6774        Some((query, selection_anchor_range))
 6775    }
 6776
 6777    fn update_selection_occurrence_highlights(
 6778        &mut self,
 6779        query_text: String,
 6780        query_range: Range<Anchor>,
 6781        multi_buffer_range_to_query: Range<Point>,
 6782        use_debounce: bool,
 6783        window: &mut Window,
 6784        cx: &mut Context<Editor>,
 6785    ) -> Task<()> {
 6786        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6787        cx.spawn_in(window, async move |editor, cx| {
 6788            if use_debounce {
 6789                cx.background_executor()
 6790                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6791                    .await;
 6792            }
 6793            let match_task = cx.background_spawn(async move {
 6794                let buffer_ranges = multi_buffer_snapshot
 6795                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6796                    .into_iter()
 6797                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6798                let mut match_ranges = Vec::new();
 6799                let Ok(regex) = project::search::SearchQuery::text(
 6800                    query_text.clone(),
 6801                    false,
 6802                    false,
 6803                    false,
 6804                    Default::default(),
 6805                    Default::default(),
 6806                    false,
 6807                    None,
 6808                ) else {
 6809                    return Vec::default();
 6810                };
 6811                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6812                    match_ranges.extend(
 6813                        regex
 6814                            .search(&buffer_snapshot, Some(search_range.clone()))
 6815                            .await
 6816                            .into_iter()
 6817                            .filter_map(|match_range| {
 6818                                let match_start = buffer_snapshot
 6819                                    .anchor_after(search_range.start + match_range.start);
 6820                                let match_end = buffer_snapshot
 6821                                    .anchor_before(search_range.start + match_range.end);
 6822                                let match_anchor_range = Anchor::range_in_buffer(
 6823                                    excerpt_id,
 6824                                    buffer_snapshot.remote_id(),
 6825                                    match_start..match_end,
 6826                                );
 6827                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6828                            }),
 6829                    );
 6830                }
 6831                match_ranges
 6832            });
 6833            let match_ranges = match_task.await;
 6834            editor
 6835                .update_in(cx, |editor, _, cx| {
 6836                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6837                    if !match_ranges.is_empty() {
 6838                        editor.highlight_background::<SelectedTextHighlight>(
 6839                            &match_ranges,
 6840                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6841                            cx,
 6842                        )
 6843                    }
 6844                })
 6845                .log_err();
 6846        })
 6847    }
 6848
 6849    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6850        struct NewlineFold;
 6851        let type_id = std::any::TypeId::of::<NewlineFold>();
 6852        if !self.mode.is_single_line() {
 6853            return;
 6854        }
 6855        let snapshot = self.snapshot(window, cx);
 6856        if snapshot.buffer_snapshot.max_point().row == 0 {
 6857            return;
 6858        }
 6859        let task = cx.background_spawn(async move {
 6860            let new_newlines = snapshot
 6861                .buffer_chars_at(0)
 6862                .filter_map(|(c, i)| {
 6863                    if c == '\n' {
 6864                        Some(
 6865                            snapshot.buffer_snapshot.anchor_after(i)
 6866                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6867                        )
 6868                    } else {
 6869                        None
 6870                    }
 6871                })
 6872                .collect::<Vec<_>>();
 6873            let existing_newlines = snapshot
 6874                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6875                .filter_map(|fold| {
 6876                    if fold.placeholder.type_tag == Some(type_id) {
 6877                        Some(fold.range.start..fold.range.end)
 6878                    } else {
 6879                        None
 6880                    }
 6881                })
 6882                .collect::<Vec<_>>();
 6883
 6884            (new_newlines, existing_newlines)
 6885        });
 6886        self.folding_newlines = cx.spawn(async move |this, cx| {
 6887            let (new_newlines, existing_newlines) = task.await;
 6888            if new_newlines == existing_newlines {
 6889                return;
 6890            }
 6891            let placeholder = FoldPlaceholder {
 6892                render: Arc::new(move |_, _, cx| {
 6893                    div()
 6894                        .bg(cx.theme().status().hint_background)
 6895                        .border_b_1()
 6896                        .size_full()
 6897                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6898                        .border_color(cx.theme().status().hint)
 6899                        .child("\\n")
 6900                        .into_any()
 6901                }),
 6902                constrain_width: false,
 6903                merge_adjacent: false,
 6904                type_tag: Some(type_id),
 6905            };
 6906            let creases = new_newlines
 6907                .into_iter()
 6908                .map(|range| Crease::simple(range, placeholder.clone()))
 6909                .collect();
 6910            this.update(cx, |this, cx| {
 6911                this.display_map.update(cx, |display_map, cx| {
 6912                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6913                    display_map.fold(creases, cx);
 6914                });
 6915            })
 6916            .ok();
 6917        });
 6918    }
 6919
 6920    fn refresh_selected_text_highlights(
 6921        &mut self,
 6922        on_buffer_edit: bool,
 6923        window: &mut Window,
 6924        cx: &mut Context<Editor>,
 6925    ) {
 6926        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6927        else {
 6928            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6929            self.quick_selection_highlight_task.take();
 6930            self.debounced_selection_highlight_task.take();
 6931            return;
 6932        };
 6933        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6934        if on_buffer_edit
 6935            || self
 6936                .quick_selection_highlight_task
 6937                .as_ref()
 6938                .map_or(true, |(prev_anchor_range, _)| {
 6939                    prev_anchor_range != &query_range
 6940                })
 6941        {
 6942            let multi_buffer_visible_start = self
 6943                .scroll_manager
 6944                .anchor()
 6945                .anchor
 6946                .to_point(&multi_buffer_snapshot);
 6947            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6948                multi_buffer_visible_start
 6949                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6950                Bias::Left,
 6951            );
 6952            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6953            self.quick_selection_highlight_task = Some((
 6954                query_range.clone(),
 6955                self.update_selection_occurrence_highlights(
 6956                    query_text.clone(),
 6957                    query_range.clone(),
 6958                    multi_buffer_visible_range,
 6959                    false,
 6960                    window,
 6961                    cx,
 6962                ),
 6963            ));
 6964        }
 6965        if on_buffer_edit
 6966            || self
 6967                .debounced_selection_highlight_task
 6968                .as_ref()
 6969                .map_or(true, |(prev_anchor_range, _)| {
 6970                    prev_anchor_range != &query_range
 6971                })
 6972        {
 6973            let multi_buffer_start = multi_buffer_snapshot
 6974                .anchor_before(0)
 6975                .to_point(&multi_buffer_snapshot);
 6976            let multi_buffer_end = multi_buffer_snapshot
 6977                .anchor_after(multi_buffer_snapshot.len())
 6978                .to_point(&multi_buffer_snapshot);
 6979            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6980            self.debounced_selection_highlight_task = Some((
 6981                query_range.clone(),
 6982                self.update_selection_occurrence_highlights(
 6983                    query_text,
 6984                    query_range,
 6985                    multi_buffer_full_range,
 6986                    true,
 6987                    window,
 6988                    cx,
 6989                ),
 6990            ));
 6991        }
 6992    }
 6993
 6994    pub fn refresh_edit_prediction(
 6995        &mut self,
 6996        debounce: bool,
 6997        user_requested: bool,
 6998        window: &mut Window,
 6999        cx: &mut Context<Self>,
 7000    ) -> Option<()> {
 7001        if DisableAiSettings::get_global(cx).disable_ai {
 7002            return None;
 7003        }
 7004
 7005        let provider = self.edit_prediction_provider()?;
 7006        let cursor = self.selections.newest_anchor().head();
 7007        let (buffer, cursor_buffer_position) =
 7008            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7009
 7010        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7011            self.discard_edit_prediction(false, cx);
 7012            return None;
 7013        }
 7014
 7015        if !user_requested
 7016            && (!self.should_show_edit_predictions()
 7017                || !self.is_focused(window)
 7018                || buffer.read(cx).is_empty())
 7019        {
 7020            self.discard_edit_prediction(false, cx);
 7021            return None;
 7022        }
 7023
 7024        self.update_visible_edit_prediction(window, cx);
 7025        provider.refresh(
 7026            self.project.clone(),
 7027            buffer,
 7028            cursor_buffer_position,
 7029            debounce,
 7030            cx,
 7031        );
 7032        Some(())
 7033    }
 7034
 7035    fn show_edit_predictions_in_menu(&self) -> bool {
 7036        match self.edit_prediction_settings {
 7037            EditPredictionSettings::Disabled => false,
 7038            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7039        }
 7040    }
 7041
 7042    pub fn edit_predictions_enabled(&self) -> bool {
 7043        match self.edit_prediction_settings {
 7044            EditPredictionSettings::Disabled => false,
 7045            EditPredictionSettings::Enabled { .. } => true,
 7046        }
 7047    }
 7048
 7049    fn edit_prediction_requires_modifier(&self) -> bool {
 7050        match self.edit_prediction_settings {
 7051            EditPredictionSettings::Disabled => false,
 7052            EditPredictionSettings::Enabled {
 7053                preview_requires_modifier,
 7054                ..
 7055            } => preview_requires_modifier,
 7056        }
 7057    }
 7058
 7059    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7060        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7061            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7062            self.discard_edit_prediction(false, cx);
 7063        } else {
 7064            let selection = self.selections.newest_anchor();
 7065            let cursor = selection.head();
 7066
 7067            if let Some((buffer, cursor_buffer_position)) =
 7068                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7069            {
 7070                self.edit_prediction_settings =
 7071                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7072            }
 7073        }
 7074    }
 7075
 7076    fn edit_prediction_settings_at_position(
 7077        &self,
 7078        buffer: &Entity<Buffer>,
 7079        buffer_position: language::Anchor,
 7080        cx: &App,
 7081    ) -> EditPredictionSettings {
 7082        if !self.mode.is_full()
 7083            || !self.show_edit_predictions_override.unwrap_or(true)
 7084            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7085        {
 7086            return EditPredictionSettings::Disabled;
 7087        }
 7088
 7089        let buffer = buffer.read(cx);
 7090
 7091        let file = buffer.file();
 7092
 7093        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7094            return EditPredictionSettings::Disabled;
 7095        };
 7096
 7097        let by_provider = matches!(
 7098            self.menu_edit_predictions_policy,
 7099            MenuEditPredictionsPolicy::ByProvider
 7100        );
 7101
 7102        let show_in_menu = by_provider
 7103            && self
 7104                .edit_prediction_provider
 7105                .as_ref()
 7106                .map_or(false, |provider| {
 7107                    provider.provider.show_completions_in_menu()
 7108                });
 7109
 7110        let preview_requires_modifier =
 7111            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7112
 7113        EditPredictionSettings::Enabled {
 7114            show_in_menu,
 7115            preview_requires_modifier,
 7116        }
 7117    }
 7118
 7119    fn should_show_edit_predictions(&self) -> bool {
 7120        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7121    }
 7122
 7123    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7124        matches!(
 7125            self.edit_prediction_preview,
 7126            EditPredictionPreview::Active { .. }
 7127        )
 7128    }
 7129
 7130    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7131        let cursor = self.selections.newest_anchor().head();
 7132        if let Some((buffer, cursor_position)) =
 7133            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7134        {
 7135            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7136        } else {
 7137            false
 7138        }
 7139    }
 7140
 7141    pub fn supports_minimap(&self, cx: &App) -> bool {
 7142        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7143    }
 7144
 7145    fn edit_predictions_enabled_in_buffer(
 7146        &self,
 7147        buffer: &Entity<Buffer>,
 7148        buffer_position: language::Anchor,
 7149        cx: &App,
 7150    ) -> bool {
 7151        maybe!({
 7152            if self.read_only(cx) {
 7153                return Some(false);
 7154            }
 7155            let provider = self.edit_prediction_provider()?;
 7156            if !provider.is_enabled(&buffer, buffer_position, cx) {
 7157                return Some(false);
 7158            }
 7159            let buffer = buffer.read(cx);
 7160            let Some(file) = buffer.file() else {
 7161                return Some(true);
 7162            };
 7163            let settings = all_language_settings(Some(file), cx);
 7164            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7165        })
 7166        .unwrap_or(false)
 7167    }
 7168
 7169    fn cycle_edit_prediction(
 7170        &mut self,
 7171        direction: Direction,
 7172        window: &mut Window,
 7173        cx: &mut Context<Self>,
 7174    ) -> Option<()> {
 7175        let provider = self.edit_prediction_provider()?;
 7176        let cursor = self.selections.newest_anchor().head();
 7177        let (buffer, cursor_buffer_position) =
 7178            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7179        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7180            return None;
 7181        }
 7182
 7183        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7184        self.update_visible_edit_prediction(window, cx);
 7185
 7186        Some(())
 7187    }
 7188
 7189    pub fn show_edit_prediction(
 7190        &mut self,
 7191        _: &ShowEditPrediction,
 7192        window: &mut Window,
 7193        cx: &mut Context<Self>,
 7194    ) {
 7195        if !self.has_active_edit_prediction() {
 7196            self.refresh_edit_prediction(false, true, window, cx);
 7197            return;
 7198        }
 7199
 7200        self.update_visible_edit_prediction(window, cx);
 7201    }
 7202
 7203    pub fn display_cursor_names(
 7204        &mut self,
 7205        _: &DisplayCursorNames,
 7206        window: &mut Window,
 7207        cx: &mut Context<Self>,
 7208    ) {
 7209        self.show_cursor_names(window, cx);
 7210    }
 7211
 7212    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7213        self.show_cursor_names = true;
 7214        cx.notify();
 7215        cx.spawn_in(window, async move |this, cx| {
 7216            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7217            this.update(cx, |this, cx| {
 7218                this.show_cursor_names = false;
 7219                cx.notify()
 7220            })
 7221            .ok()
 7222        })
 7223        .detach();
 7224    }
 7225
 7226    pub fn next_edit_prediction(
 7227        &mut self,
 7228        _: &NextEditPrediction,
 7229        window: &mut Window,
 7230        cx: &mut Context<Self>,
 7231    ) {
 7232        if self.has_active_edit_prediction() {
 7233            self.cycle_edit_prediction(Direction::Next, window, cx);
 7234        } else {
 7235            let is_copilot_disabled = self
 7236                .refresh_edit_prediction(false, true, window, cx)
 7237                .is_none();
 7238            if is_copilot_disabled {
 7239                cx.propagate();
 7240            }
 7241        }
 7242    }
 7243
 7244    pub fn previous_edit_prediction(
 7245        &mut self,
 7246        _: &PreviousEditPrediction,
 7247        window: &mut Window,
 7248        cx: &mut Context<Self>,
 7249    ) {
 7250        if self.has_active_edit_prediction() {
 7251            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7252        } else {
 7253            let is_copilot_disabled = self
 7254                .refresh_edit_prediction(false, true, window, cx)
 7255                .is_none();
 7256            if is_copilot_disabled {
 7257                cx.propagate();
 7258            }
 7259        }
 7260    }
 7261
 7262    pub fn accept_edit_prediction(
 7263        &mut self,
 7264        _: &AcceptEditPrediction,
 7265        window: &mut Window,
 7266        cx: &mut Context<Self>,
 7267    ) {
 7268        if self.show_edit_predictions_in_menu() {
 7269            self.hide_context_menu(window, cx);
 7270        }
 7271
 7272        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7273            return;
 7274        };
 7275
 7276        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7277
 7278        match &active_edit_prediction.completion {
 7279            EditPrediction::Move { target, .. } => {
 7280                let target = *target;
 7281
 7282                if let Some(position_map) = &self.last_position_map {
 7283                    if position_map
 7284                        .visible_row_range
 7285                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7286                        || !self.edit_prediction_requires_modifier()
 7287                    {
 7288                        self.unfold_ranges(&[target..target], true, false, cx);
 7289                        // Note that this is also done in vim's handler of the Tab action.
 7290                        self.change_selections(
 7291                            SelectionEffects::scroll(Autoscroll::newest()),
 7292                            window,
 7293                            cx,
 7294                            |selections| {
 7295                                selections.select_anchor_ranges([target..target]);
 7296                            },
 7297                        );
 7298                        self.clear_row_highlights::<EditPredictionPreview>();
 7299
 7300                        self.edit_prediction_preview
 7301                            .set_previous_scroll_position(None);
 7302                    } else {
 7303                        self.edit_prediction_preview
 7304                            .set_previous_scroll_position(Some(
 7305                                position_map.snapshot.scroll_anchor,
 7306                            ));
 7307
 7308                        self.highlight_rows::<EditPredictionPreview>(
 7309                            target..target,
 7310                            cx.theme().colors().editor_highlighted_line_background,
 7311                            RowHighlightOptions {
 7312                                autoscroll: true,
 7313                                ..Default::default()
 7314                            },
 7315                            cx,
 7316                        );
 7317                        self.request_autoscroll(Autoscroll::fit(), cx);
 7318                    }
 7319                }
 7320            }
 7321            EditPrediction::Edit { edits, .. } => {
 7322                if let Some(provider) = self.edit_prediction_provider() {
 7323                    provider.accept(cx);
 7324                }
 7325
 7326                // Store the transaction ID and selections before applying the edit
 7327                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7328
 7329                let snapshot = self.buffer.read(cx).snapshot(cx);
 7330                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7331
 7332                self.buffer.update(cx, |buffer, cx| {
 7333                    buffer.edit(edits.iter().cloned(), None, cx)
 7334                });
 7335
 7336                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7337                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7338                });
 7339
 7340                let selections = self.selections.disjoint_anchors();
 7341                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7342                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7343                    if has_new_transaction {
 7344                        self.selection_history
 7345                            .insert_transaction(transaction_id_now, selections);
 7346                    }
 7347                }
 7348
 7349                self.update_visible_edit_prediction(window, cx);
 7350                if self.active_edit_prediction.is_none() {
 7351                    self.refresh_edit_prediction(true, true, window, cx);
 7352                }
 7353
 7354                cx.notify();
 7355            }
 7356        }
 7357
 7358        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7359    }
 7360
 7361    pub fn accept_partial_edit_prediction(
 7362        &mut self,
 7363        _: &AcceptPartialEditPrediction,
 7364        window: &mut Window,
 7365        cx: &mut Context<Self>,
 7366    ) {
 7367        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7368            return;
 7369        };
 7370        if self.selections.count() != 1 {
 7371            return;
 7372        }
 7373
 7374        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7375
 7376        match &active_edit_prediction.completion {
 7377            EditPrediction::Move { target, .. } => {
 7378                let target = *target;
 7379                self.change_selections(
 7380                    SelectionEffects::scroll(Autoscroll::newest()),
 7381                    window,
 7382                    cx,
 7383                    |selections| {
 7384                        selections.select_anchor_ranges([target..target]);
 7385                    },
 7386                );
 7387            }
 7388            EditPrediction::Edit { edits, .. } => {
 7389                // Find an insertion that starts at the cursor position.
 7390                let snapshot = self.buffer.read(cx).snapshot(cx);
 7391                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7392                let insertion = edits.iter().find_map(|(range, text)| {
 7393                    let range = range.to_offset(&snapshot);
 7394                    if range.is_empty() && range.start == cursor_offset {
 7395                        Some(text)
 7396                    } else {
 7397                        None
 7398                    }
 7399                });
 7400
 7401                if let Some(text) = insertion {
 7402                    let mut partial_completion = text
 7403                        .chars()
 7404                        .by_ref()
 7405                        .take_while(|c| c.is_alphabetic())
 7406                        .collect::<String>();
 7407                    if partial_completion.is_empty() {
 7408                        partial_completion = text
 7409                            .chars()
 7410                            .by_ref()
 7411                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7412                            .collect::<String>();
 7413                    }
 7414
 7415                    cx.emit(EditorEvent::InputHandled {
 7416                        utf16_range_to_replace: None,
 7417                        text: partial_completion.clone().into(),
 7418                    });
 7419
 7420                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7421
 7422                    self.refresh_edit_prediction(true, true, window, cx);
 7423                    cx.notify();
 7424                } else {
 7425                    self.accept_edit_prediction(&Default::default(), window, cx);
 7426                }
 7427            }
 7428        }
 7429    }
 7430
 7431    fn discard_edit_prediction(
 7432        &mut self,
 7433        should_report_edit_prediction_event: bool,
 7434        cx: &mut Context<Self>,
 7435    ) -> bool {
 7436        if should_report_edit_prediction_event {
 7437            let completion_id = self
 7438                .active_edit_prediction
 7439                .as_ref()
 7440                .and_then(|active_completion| active_completion.completion_id.clone());
 7441
 7442            self.report_edit_prediction_event(completion_id, false, cx);
 7443        }
 7444
 7445        if let Some(provider) = self.edit_prediction_provider() {
 7446            provider.discard(cx);
 7447        }
 7448
 7449        self.take_active_edit_prediction(cx)
 7450    }
 7451
 7452    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7453        let Some(provider) = self.edit_prediction_provider() else {
 7454            return;
 7455        };
 7456
 7457        let Some((_, buffer, _)) = self
 7458            .buffer
 7459            .read(cx)
 7460            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7461        else {
 7462            return;
 7463        };
 7464
 7465        let extension = buffer
 7466            .read(cx)
 7467            .file()
 7468            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7469
 7470        let event_type = match accepted {
 7471            true => "Edit Prediction Accepted",
 7472            false => "Edit Prediction Discarded",
 7473        };
 7474        telemetry::event!(
 7475            event_type,
 7476            provider = provider.name(),
 7477            prediction_id = id,
 7478            suggestion_accepted = accepted,
 7479            file_extension = extension,
 7480        );
 7481    }
 7482
 7483    pub fn has_active_edit_prediction(&self) -> bool {
 7484        self.active_edit_prediction.is_some()
 7485    }
 7486
 7487    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7488        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7489            return false;
 7490        };
 7491
 7492        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7493        self.clear_highlights::<EditPredictionHighlight>(cx);
 7494        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7495        true
 7496    }
 7497
 7498    /// Returns true when we're displaying the edit prediction popover below the cursor
 7499    /// like we are not previewing and the LSP autocomplete menu is visible
 7500    /// or we are in `when_holding_modifier` mode.
 7501    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7502        if self.edit_prediction_preview_is_active()
 7503            || !self.show_edit_predictions_in_menu()
 7504            || !self.edit_predictions_enabled()
 7505        {
 7506            return false;
 7507        }
 7508
 7509        if self.has_visible_completions_menu() {
 7510            return true;
 7511        }
 7512
 7513        has_completion && self.edit_prediction_requires_modifier()
 7514    }
 7515
 7516    fn handle_modifiers_changed(
 7517        &mut self,
 7518        modifiers: Modifiers,
 7519        position_map: &PositionMap,
 7520        window: &mut Window,
 7521        cx: &mut Context<Self>,
 7522    ) {
 7523        if self.show_edit_predictions_in_menu() {
 7524            self.update_edit_prediction_preview(&modifiers, window, cx);
 7525        }
 7526
 7527        self.update_selection_mode(&modifiers, position_map, window, cx);
 7528
 7529        let mouse_position = window.mouse_position();
 7530        if !position_map.text_hitbox.is_hovered(window) {
 7531            return;
 7532        }
 7533
 7534        self.update_hovered_link(
 7535            position_map.point_for_position(mouse_position),
 7536            &position_map.snapshot,
 7537            modifiers,
 7538            window,
 7539            cx,
 7540        )
 7541    }
 7542
 7543    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7544        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7545        if invert {
 7546            match multi_cursor_setting {
 7547                MultiCursorModifier::Alt => modifiers.alt,
 7548                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7549            }
 7550        } else {
 7551            match multi_cursor_setting {
 7552                MultiCursorModifier::Alt => modifiers.secondary(),
 7553                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7554            }
 7555        }
 7556    }
 7557
 7558    fn columnar_selection_mode(
 7559        modifiers: &Modifiers,
 7560        cx: &mut Context<Self>,
 7561    ) -> Option<ColumnarMode> {
 7562        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7563            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7564                Some(ColumnarMode::FromMouse)
 7565            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7566                Some(ColumnarMode::FromSelection)
 7567            } else {
 7568                None
 7569            }
 7570        } else {
 7571            None
 7572        }
 7573    }
 7574
 7575    fn update_selection_mode(
 7576        &mut self,
 7577        modifiers: &Modifiers,
 7578        position_map: &PositionMap,
 7579        window: &mut Window,
 7580        cx: &mut Context<Self>,
 7581    ) {
 7582        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7583            return;
 7584        };
 7585        if self.selections.pending.is_none() {
 7586            return;
 7587        }
 7588
 7589        let mouse_position = window.mouse_position();
 7590        let point_for_position = position_map.point_for_position(mouse_position);
 7591        let position = point_for_position.previous_valid;
 7592
 7593        self.select(
 7594            SelectPhase::BeginColumnar {
 7595                position,
 7596                reset: false,
 7597                mode,
 7598                goal_column: point_for_position.exact_unclipped.column(),
 7599            },
 7600            window,
 7601            cx,
 7602        );
 7603    }
 7604
 7605    fn update_edit_prediction_preview(
 7606        &mut self,
 7607        modifiers: &Modifiers,
 7608        window: &mut Window,
 7609        cx: &mut Context<Self>,
 7610    ) {
 7611        let mut modifiers_held = false;
 7612        if let Some(accept_keystroke) = self
 7613            .accept_edit_prediction_keybind(false, window, cx)
 7614            .keystroke()
 7615        {
 7616            modifiers_held = modifiers_held
 7617                || (&accept_keystroke.modifiers == modifiers
 7618                    && accept_keystroke.modifiers.modified());
 7619        };
 7620        if let Some(accept_partial_keystroke) = self
 7621            .accept_edit_prediction_keybind(true, window, cx)
 7622            .keystroke()
 7623        {
 7624            modifiers_held = modifiers_held
 7625                || (&accept_partial_keystroke.modifiers == modifiers
 7626                    && accept_partial_keystroke.modifiers.modified());
 7627        }
 7628
 7629        if modifiers_held {
 7630            if matches!(
 7631                self.edit_prediction_preview,
 7632                EditPredictionPreview::Inactive { .. }
 7633            ) {
 7634                self.edit_prediction_preview = EditPredictionPreview::Active {
 7635                    previous_scroll_position: None,
 7636                    since: Instant::now(),
 7637                };
 7638
 7639                self.update_visible_edit_prediction(window, cx);
 7640                cx.notify();
 7641            }
 7642        } else if let EditPredictionPreview::Active {
 7643            previous_scroll_position,
 7644            since,
 7645        } = self.edit_prediction_preview
 7646        {
 7647            if let (Some(previous_scroll_position), Some(position_map)) =
 7648                (previous_scroll_position, self.last_position_map.as_ref())
 7649            {
 7650                self.set_scroll_position(
 7651                    previous_scroll_position
 7652                        .scroll_position(&position_map.snapshot.display_snapshot),
 7653                    window,
 7654                    cx,
 7655                );
 7656            }
 7657
 7658            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7659                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7660            };
 7661            self.clear_row_highlights::<EditPredictionPreview>();
 7662            self.update_visible_edit_prediction(window, cx);
 7663            cx.notify();
 7664        }
 7665    }
 7666
 7667    fn update_visible_edit_prediction(
 7668        &mut self,
 7669        _window: &mut Window,
 7670        cx: &mut Context<Self>,
 7671    ) -> Option<()> {
 7672        if DisableAiSettings::get_global(cx).disable_ai {
 7673            return None;
 7674        }
 7675
 7676        let selection = self.selections.newest_anchor();
 7677        let cursor = selection.head();
 7678        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7679        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7680        let excerpt_id = cursor.excerpt_id;
 7681
 7682        let show_in_menu = self.show_edit_predictions_in_menu();
 7683        let completions_menu_has_precedence = !show_in_menu
 7684            && (self.context_menu.borrow().is_some()
 7685                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7686
 7687        if completions_menu_has_precedence
 7688            || !offset_selection.is_empty()
 7689            || self
 7690                .active_edit_prediction
 7691                .as_ref()
 7692                .map_or(false, |completion| {
 7693                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7694                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7695                    !invalidation_range.contains(&offset_selection.head())
 7696                })
 7697        {
 7698            self.discard_edit_prediction(false, cx);
 7699            return None;
 7700        }
 7701
 7702        self.take_active_edit_prediction(cx);
 7703        let Some(provider) = self.edit_prediction_provider() else {
 7704            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7705            return None;
 7706        };
 7707
 7708        let (buffer, cursor_buffer_position) =
 7709            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7710
 7711        self.edit_prediction_settings =
 7712            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7713
 7714        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7715
 7716        if self.edit_prediction_indent_conflict {
 7717            let cursor_point = cursor.to_point(&multibuffer);
 7718
 7719            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7720
 7721            if let Some((_, indent)) = indents.iter().next() {
 7722                if indent.len == cursor_point.column {
 7723                    self.edit_prediction_indent_conflict = false;
 7724                }
 7725            }
 7726        }
 7727
 7728        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7729        let edits = edit_prediction
 7730            .edits
 7731            .into_iter()
 7732            .flat_map(|(range, new_text)| {
 7733                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7734                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7735                Some((start..end, new_text))
 7736            })
 7737            .collect::<Vec<_>>();
 7738        if edits.is_empty() {
 7739            return None;
 7740        }
 7741
 7742        let first_edit_start = edits.first().unwrap().0.start;
 7743        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7744        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7745
 7746        let last_edit_end = edits.last().unwrap().0.end;
 7747        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7748        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7749
 7750        let cursor_row = cursor.to_point(&multibuffer).row;
 7751
 7752        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7753
 7754        let mut inlay_ids = Vec::new();
 7755        let invalidation_row_range;
 7756        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7757            Some(cursor_row..edit_end_row)
 7758        } else if cursor_row > edit_end_row {
 7759            Some(edit_start_row..cursor_row)
 7760        } else {
 7761            None
 7762        };
 7763        let is_move =
 7764            move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode;
 7765        let completion = if is_move {
 7766            invalidation_row_range =
 7767                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7768            let target = first_edit_start;
 7769            EditPrediction::Move { target, snapshot }
 7770        } else {
 7771            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7772                && !self.edit_predictions_hidden_for_vim_mode;
 7773
 7774            if show_completions_in_buffer {
 7775                if edits
 7776                    .iter()
 7777                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7778                {
 7779                    let mut inlays = Vec::new();
 7780                    for (range, new_text) in &edits {
 7781                        let inlay = Inlay::edit_prediction(
 7782                            post_inc(&mut self.next_inlay_id),
 7783                            range.start,
 7784                            new_text.as_str(),
 7785                        );
 7786                        inlay_ids.push(inlay.id);
 7787                        inlays.push(inlay);
 7788                    }
 7789
 7790                    self.splice_inlays(&[], inlays, cx);
 7791                } else {
 7792                    let background_color = cx.theme().status().deleted_background;
 7793                    self.highlight_text::<EditPredictionHighlight>(
 7794                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7795                        HighlightStyle {
 7796                            background_color: Some(background_color),
 7797                            ..Default::default()
 7798                        },
 7799                        cx,
 7800                    );
 7801                }
 7802            }
 7803
 7804            invalidation_row_range = edit_start_row..edit_end_row;
 7805
 7806            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7807                if provider.show_tab_accept_marker() {
 7808                    EditDisplayMode::TabAccept
 7809                } else {
 7810                    EditDisplayMode::Inline
 7811                }
 7812            } else {
 7813                EditDisplayMode::DiffPopover
 7814            };
 7815
 7816            EditPrediction::Edit {
 7817                edits,
 7818                edit_preview: edit_prediction.edit_preview,
 7819                display_mode,
 7820                snapshot,
 7821            }
 7822        };
 7823
 7824        let invalidation_range = multibuffer
 7825            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7826            ..multibuffer.anchor_after(Point::new(
 7827                invalidation_row_range.end,
 7828                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7829            ));
 7830
 7831        self.stale_edit_prediction_in_menu = None;
 7832        self.active_edit_prediction = Some(EditPredictionState {
 7833            inlay_ids,
 7834            completion,
 7835            completion_id: edit_prediction.id,
 7836            invalidation_range,
 7837        });
 7838
 7839        cx.notify();
 7840
 7841        Some(())
 7842    }
 7843
 7844    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7845        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7846    }
 7847
 7848    fn clear_tasks(&mut self) {
 7849        self.tasks.clear()
 7850    }
 7851
 7852    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7853        if self.tasks.insert(key, value).is_some() {
 7854            // This case should hopefully be rare, but just in case...
 7855            log::error!(
 7856                "multiple different run targets found on a single line, only the last target will be rendered"
 7857            )
 7858        }
 7859    }
 7860
 7861    /// Get all display points of breakpoints that will be rendered within editor
 7862    ///
 7863    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7864    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7865    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7866    fn active_breakpoints(
 7867        &self,
 7868        range: Range<DisplayRow>,
 7869        window: &mut Window,
 7870        cx: &mut Context<Self>,
 7871    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7872        let mut breakpoint_display_points = HashMap::default();
 7873
 7874        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7875            return breakpoint_display_points;
 7876        };
 7877
 7878        let snapshot = self.snapshot(window, cx);
 7879
 7880        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7881        let Some(project) = self.project.as_ref() else {
 7882            return breakpoint_display_points;
 7883        };
 7884
 7885        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7886            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7887
 7888        for (buffer_snapshot, range, excerpt_id) in
 7889            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7890        {
 7891            let Some(buffer) = project
 7892                .read(cx)
 7893                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7894            else {
 7895                continue;
 7896            };
 7897            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7898                &buffer,
 7899                Some(
 7900                    buffer_snapshot.anchor_before(range.start)
 7901                        ..buffer_snapshot.anchor_after(range.end),
 7902                ),
 7903                buffer_snapshot,
 7904                cx,
 7905            );
 7906            for (breakpoint, state) in breakpoints {
 7907                let multi_buffer_anchor =
 7908                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7909                let position = multi_buffer_anchor
 7910                    .to_point(&multi_buffer_snapshot)
 7911                    .to_display_point(&snapshot);
 7912
 7913                breakpoint_display_points.insert(
 7914                    position.row(),
 7915                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7916                );
 7917            }
 7918        }
 7919
 7920        breakpoint_display_points
 7921    }
 7922
 7923    fn breakpoint_context_menu(
 7924        &self,
 7925        anchor: Anchor,
 7926        window: &mut Window,
 7927        cx: &mut Context<Self>,
 7928    ) -> Entity<ui::ContextMenu> {
 7929        let weak_editor = cx.weak_entity();
 7930        let focus_handle = self.focus_handle(cx);
 7931
 7932        let row = self
 7933            .buffer
 7934            .read(cx)
 7935            .snapshot(cx)
 7936            .summary_for_anchor::<Point>(&anchor)
 7937            .row;
 7938
 7939        let breakpoint = self
 7940            .breakpoint_at_row(row, window, cx)
 7941            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7942
 7943        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7944            "Edit Log Breakpoint"
 7945        } else {
 7946            "Set Log Breakpoint"
 7947        };
 7948
 7949        let condition_breakpoint_msg = if breakpoint
 7950            .as_ref()
 7951            .is_some_and(|bp| bp.1.condition.is_some())
 7952        {
 7953            "Edit Condition Breakpoint"
 7954        } else {
 7955            "Set Condition Breakpoint"
 7956        };
 7957
 7958        let hit_condition_breakpoint_msg = if breakpoint
 7959            .as_ref()
 7960            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7961        {
 7962            "Edit Hit Condition Breakpoint"
 7963        } else {
 7964            "Set Hit Condition Breakpoint"
 7965        };
 7966
 7967        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7968            "Unset Breakpoint"
 7969        } else {
 7970            "Set Breakpoint"
 7971        };
 7972
 7973        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7974
 7975        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7976            BreakpointState::Enabled => Some("Disable"),
 7977            BreakpointState::Disabled => Some("Enable"),
 7978        });
 7979
 7980        let (anchor, breakpoint) =
 7981            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7982
 7983        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7984            menu.on_blur_subscription(Subscription::new(|| {}))
 7985                .context(focus_handle)
 7986                .when(run_to_cursor, |this| {
 7987                    let weak_editor = weak_editor.clone();
 7988                    this.entry("Run to cursor", None, move |window, cx| {
 7989                        weak_editor
 7990                            .update(cx, |editor, cx| {
 7991                                editor.change_selections(
 7992                                    SelectionEffects::no_scroll(),
 7993                                    window,
 7994                                    cx,
 7995                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 7996                                );
 7997                            })
 7998                            .ok();
 7999
 8000                        window.dispatch_action(Box::new(RunToCursor), cx);
 8001                    })
 8002                    .separator()
 8003                })
 8004                .when_some(toggle_state_msg, |this, msg| {
 8005                    this.entry(msg, None, {
 8006                        let weak_editor = weak_editor.clone();
 8007                        let breakpoint = breakpoint.clone();
 8008                        move |_window, cx| {
 8009                            weak_editor
 8010                                .update(cx, |this, cx| {
 8011                                    this.edit_breakpoint_at_anchor(
 8012                                        anchor,
 8013                                        breakpoint.as_ref().clone(),
 8014                                        BreakpointEditAction::InvertState,
 8015                                        cx,
 8016                                    );
 8017                                })
 8018                                .log_err();
 8019                        }
 8020                    })
 8021                })
 8022                .entry(set_breakpoint_msg, None, {
 8023                    let weak_editor = weak_editor.clone();
 8024                    let breakpoint = breakpoint.clone();
 8025                    move |_window, cx| {
 8026                        weak_editor
 8027                            .update(cx, |this, cx| {
 8028                                this.edit_breakpoint_at_anchor(
 8029                                    anchor,
 8030                                    breakpoint.as_ref().clone(),
 8031                                    BreakpointEditAction::Toggle,
 8032                                    cx,
 8033                                );
 8034                            })
 8035                            .log_err();
 8036                    }
 8037                })
 8038                .entry(log_breakpoint_msg, None, {
 8039                    let breakpoint = breakpoint.clone();
 8040                    let weak_editor = weak_editor.clone();
 8041                    move |window, cx| {
 8042                        weak_editor
 8043                            .update(cx, |this, cx| {
 8044                                this.add_edit_breakpoint_block(
 8045                                    anchor,
 8046                                    breakpoint.as_ref(),
 8047                                    BreakpointPromptEditAction::Log,
 8048                                    window,
 8049                                    cx,
 8050                                );
 8051                            })
 8052                            .log_err();
 8053                    }
 8054                })
 8055                .entry(condition_breakpoint_msg, None, {
 8056                    let breakpoint = breakpoint.clone();
 8057                    let weak_editor = weak_editor.clone();
 8058                    move |window, cx| {
 8059                        weak_editor
 8060                            .update(cx, |this, cx| {
 8061                                this.add_edit_breakpoint_block(
 8062                                    anchor,
 8063                                    breakpoint.as_ref(),
 8064                                    BreakpointPromptEditAction::Condition,
 8065                                    window,
 8066                                    cx,
 8067                                );
 8068                            })
 8069                            .log_err();
 8070                    }
 8071                })
 8072                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8073                    weak_editor
 8074                        .update(cx, |this, cx| {
 8075                            this.add_edit_breakpoint_block(
 8076                                anchor,
 8077                                breakpoint.as_ref(),
 8078                                BreakpointPromptEditAction::HitCondition,
 8079                                window,
 8080                                cx,
 8081                            );
 8082                        })
 8083                        .log_err();
 8084                })
 8085        })
 8086    }
 8087
 8088    fn render_breakpoint(
 8089        &self,
 8090        position: Anchor,
 8091        row: DisplayRow,
 8092        breakpoint: &Breakpoint,
 8093        state: Option<BreakpointSessionState>,
 8094        cx: &mut Context<Self>,
 8095    ) -> IconButton {
 8096        let is_rejected = state.is_some_and(|s| !s.verified);
 8097        // Is it a breakpoint that shows up when hovering over gutter?
 8098        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8099            (false, false),
 8100            |PhantomBreakpointIndicator {
 8101                 is_active,
 8102                 display_row,
 8103                 collides_with_existing_breakpoint,
 8104             }| {
 8105                (
 8106                    is_active && display_row == row,
 8107                    collides_with_existing_breakpoint,
 8108                )
 8109            },
 8110        );
 8111
 8112        let (color, icon) = {
 8113            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8114                (false, false) => ui::IconName::DebugBreakpoint,
 8115                (true, false) => ui::IconName::DebugLogBreakpoint,
 8116                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8117                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8118            };
 8119
 8120            let color = if is_phantom {
 8121                Color::Hint
 8122            } else if is_rejected {
 8123                Color::Disabled
 8124            } else {
 8125                Color::Debugger
 8126            };
 8127
 8128            (color, icon)
 8129        };
 8130
 8131        let breakpoint = Arc::from(breakpoint.clone());
 8132
 8133        let alt_as_text = gpui::Keystroke {
 8134            modifiers: Modifiers::secondary_key(),
 8135            ..Default::default()
 8136        };
 8137        let primary_action_text = if breakpoint.is_disabled() {
 8138            "Enable breakpoint"
 8139        } else if is_phantom && !collides_with_existing {
 8140            "Set breakpoint"
 8141        } else {
 8142            "Unset breakpoint"
 8143        };
 8144        let focus_handle = self.focus_handle.clone();
 8145
 8146        let meta = if is_rejected {
 8147            SharedString::from("No executable code is associated with this line.")
 8148        } else if collides_with_existing && !breakpoint.is_disabled() {
 8149            SharedString::from(format!(
 8150                "{alt_as_text}-click to disable,\nright-click for more options."
 8151            ))
 8152        } else {
 8153            SharedString::from("Right-click for more options.")
 8154        };
 8155        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8156            .icon_size(IconSize::XSmall)
 8157            .size(ui::ButtonSize::None)
 8158            .when(is_rejected, |this| {
 8159                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8160            })
 8161            .icon_color(color)
 8162            .style(ButtonStyle::Transparent)
 8163            .on_click(cx.listener({
 8164                let breakpoint = breakpoint.clone();
 8165
 8166                move |editor, event: &ClickEvent, window, cx| {
 8167                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8168                        BreakpointEditAction::InvertState
 8169                    } else {
 8170                        BreakpointEditAction::Toggle
 8171                    };
 8172
 8173                    window.focus(&editor.focus_handle(cx));
 8174                    editor.edit_breakpoint_at_anchor(
 8175                        position,
 8176                        breakpoint.as_ref().clone(),
 8177                        edit_action,
 8178                        cx,
 8179                    );
 8180                }
 8181            }))
 8182            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8183                editor.set_breakpoint_context_menu(
 8184                    row,
 8185                    Some(position),
 8186                    event.position(),
 8187                    window,
 8188                    cx,
 8189                );
 8190            }))
 8191            .tooltip(move |window, cx| {
 8192                Tooltip::with_meta_in(
 8193                    primary_action_text,
 8194                    Some(&ToggleBreakpoint),
 8195                    meta.clone(),
 8196                    &focus_handle,
 8197                    window,
 8198                    cx,
 8199                )
 8200            })
 8201    }
 8202
 8203    fn build_tasks_context(
 8204        project: &Entity<Project>,
 8205        buffer: &Entity<Buffer>,
 8206        buffer_row: u32,
 8207        tasks: &Arc<RunnableTasks>,
 8208        cx: &mut Context<Self>,
 8209    ) -> Task<Option<task::TaskContext>> {
 8210        let position = Point::new(buffer_row, tasks.column);
 8211        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8212        let location = Location {
 8213            buffer: buffer.clone(),
 8214            range: range_start..range_start,
 8215        };
 8216        // Fill in the environmental variables from the tree-sitter captures
 8217        let mut captured_task_variables = TaskVariables::default();
 8218        for (capture_name, value) in tasks.extra_variables.clone() {
 8219            captured_task_variables.insert(
 8220                task::VariableName::Custom(capture_name.into()),
 8221                value.clone(),
 8222            );
 8223        }
 8224        project.update(cx, |project, cx| {
 8225            project.task_store().update(cx, |task_store, cx| {
 8226                task_store.task_context_for_location(captured_task_variables, location, cx)
 8227            })
 8228        })
 8229    }
 8230
 8231    pub fn spawn_nearest_task(
 8232        &mut self,
 8233        action: &SpawnNearestTask,
 8234        window: &mut Window,
 8235        cx: &mut Context<Self>,
 8236    ) {
 8237        let Some((workspace, _)) = self.workspace.clone() else {
 8238            return;
 8239        };
 8240        let Some(project) = self.project.clone() else {
 8241            return;
 8242        };
 8243
 8244        // Try to find a closest, enclosing node using tree-sitter that has a task
 8245        let Some((buffer, buffer_row, tasks)) = self
 8246            .find_enclosing_node_task(cx)
 8247            // Or find the task that's closest in row-distance.
 8248            .or_else(|| self.find_closest_task(cx))
 8249        else {
 8250            return;
 8251        };
 8252
 8253        let reveal_strategy = action.reveal;
 8254        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8255        cx.spawn_in(window, async move |_, cx| {
 8256            let context = task_context.await?;
 8257            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8258
 8259            let resolved = &mut resolved_task.resolved;
 8260            resolved.reveal = reveal_strategy;
 8261
 8262            workspace
 8263                .update_in(cx, |workspace, window, cx| {
 8264                    workspace.schedule_resolved_task(
 8265                        task_source_kind,
 8266                        resolved_task,
 8267                        false,
 8268                        window,
 8269                        cx,
 8270                    );
 8271                })
 8272                .ok()
 8273        })
 8274        .detach();
 8275    }
 8276
 8277    fn find_closest_task(
 8278        &mut self,
 8279        cx: &mut Context<Self>,
 8280    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8281        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8282
 8283        let ((buffer_id, row), tasks) = self
 8284            .tasks
 8285            .iter()
 8286            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8287
 8288        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8289        let tasks = Arc::new(tasks.to_owned());
 8290        Some((buffer, *row, tasks))
 8291    }
 8292
 8293    fn find_enclosing_node_task(
 8294        &mut self,
 8295        cx: &mut Context<Self>,
 8296    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8297        let snapshot = self.buffer.read(cx).snapshot(cx);
 8298        let offset = self.selections.newest::<usize>(cx).head();
 8299        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8300        let buffer_id = excerpt.buffer().remote_id();
 8301
 8302        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8303        let mut cursor = layer.node().walk();
 8304
 8305        while cursor.goto_first_child_for_byte(offset).is_some() {
 8306            if cursor.node().end_byte() == offset {
 8307                cursor.goto_next_sibling();
 8308            }
 8309        }
 8310
 8311        // Ascend to the smallest ancestor that contains the range and has a task.
 8312        loop {
 8313            let node = cursor.node();
 8314            let node_range = node.byte_range();
 8315            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8316
 8317            // Check if this node contains our offset
 8318            if node_range.start <= offset && node_range.end >= offset {
 8319                // If it contains offset, check for task
 8320                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8321                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8322                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8323                }
 8324            }
 8325
 8326            if !cursor.goto_parent() {
 8327                break;
 8328            }
 8329        }
 8330        None
 8331    }
 8332
 8333    fn render_run_indicator(
 8334        &self,
 8335        _style: &EditorStyle,
 8336        is_active: bool,
 8337        row: DisplayRow,
 8338        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8339        cx: &mut Context<Self>,
 8340    ) -> IconButton {
 8341        let color = Color::Muted;
 8342        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8343
 8344        IconButton::new(
 8345            ("run_indicator", row.0 as usize),
 8346            ui::IconName::PlayOutlined,
 8347        )
 8348        .shape(ui::IconButtonShape::Square)
 8349        .icon_size(IconSize::XSmall)
 8350        .icon_color(color)
 8351        .toggle_state(is_active)
 8352        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8353            let quick_launch = match e {
 8354                ClickEvent::Keyboard(_) => true,
 8355                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8356            };
 8357
 8358            window.focus(&editor.focus_handle(cx));
 8359            editor.toggle_code_actions(
 8360                &ToggleCodeActions {
 8361                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8362                    quick_launch,
 8363                },
 8364                window,
 8365                cx,
 8366            );
 8367        }))
 8368        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8369            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8370        }))
 8371    }
 8372
 8373    pub fn context_menu_visible(&self) -> bool {
 8374        !self.edit_prediction_preview_is_active()
 8375            && self
 8376                .context_menu
 8377                .borrow()
 8378                .as_ref()
 8379                .map_or(false, |menu| menu.visible())
 8380    }
 8381
 8382    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8383        self.context_menu
 8384            .borrow()
 8385            .as_ref()
 8386            .map(|menu| menu.origin())
 8387    }
 8388
 8389    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8390        self.context_menu_options = Some(options);
 8391    }
 8392
 8393    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8394    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8395
 8396    fn render_edit_prediction_popover(
 8397        &mut self,
 8398        text_bounds: &Bounds<Pixels>,
 8399        content_origin: gpui::Point<Pixels>,
 8400        right_margin: Pixels,
 8401        editor_snapshot: &EditorSnapshot,
 8402        visible_row_range: Range<DisplayRow>,
 8403        scroll_top: f32,
 8404        scroll_bottom: f32,
 8405        line_layouts: &[LineWithInvisibles],
 8406        line_height: Pixels,
 8407        scroll_pixel_position: gpui::Point<Pixels>,
 8408        newest_selection_head: Option<DisplayPoint>,
 8409        editor_width: Pixels,
 8410        style: &EditorStyle,
 8411        window: &mut Window,
 8412        cx: &mut App,
 8413    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8414        if self.mode().is_minimap() {
 8415            return None;
 8416        }
 8417        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8418
 8419        if self.edit_prediction_visible_in_cursor_popover(true) {
 8420            return None;
 8421        }
 8422
 8423        match &active_edit_prediction.completion {
 8424            EditPrediction::Move { target, .. } => {
 8425                let target_display_point = target.to_display_point(editor_snapshot);
 8426
 8427                if self.edit_prediction_requires_modifier() {
 8428                    if !self.edit_prediction_preview_is_active() {
 8429                        return None;
 8430                    }
 8431
 8432                    self.render_edit_prediction_modifier_jump_popover(
 8433                        text_bounds,
 8434                        content_origin,
 8435                        visible_row_range,
 8436                        line_layouts,
 8437                        line_height,
 8438                        scroll_pixel_position,
 8439                        newest_selection_head,
 8440                        target_display_point,
 8441                        window,
 8442                        cx,
 8443                    )
 8444                } else {
 8445                    self.render_edit_prediction_eager_jump_popover(
 8446                        text_bounds,
 8447                        content_origin,
 8448                        editor_snapshot,
 8449                        visible_row_range,
 8450                        scroll_top,
 8451                        scroll_bottom,
 8452                        line_height,
 8453                        scroll_pixel_position,
 8454                        target_display_point,
 8455                        editor_width,
 8456                        window,
 8457                        cx,
 8458                    )
 8459                }
 8460            }
 8461            EditPrediction::Edit {
 8462                display_mode: EditDisplayMode::Inline,
 8463                ..
 8464            } => None,
 8465            EditPrediction::Edit {
 8466                display_mode: EditDisplayMode::TabAccept,
 8467                edits,
 8468                ..
 8469            } => {
 8470                let range = &edits.first()?.0;
 8471                let target_display_point = range.end.to_display_point(editor_snapshot);
 8472
 8473                self.render_edit_prediction_end_of_line_popover(
 8474                    "Accept",
 8475                    editor_snapshot,
 8476                    visible_row_range,
 8477                    target_display_point,
 8478                    line_height,
 8479                    scroll_pixel_position,
 8480                    content_origin,
 8481                    editor_width,
 8482                    window,
 8483                    cx,
 8484                )
 8485            }
 8486            EditPrediction::Edit {
 8487                edits,
 8488                edit_preview,
 8489                display_mode: EditDisplayMode::DiffPopover,
 8490                snapshot,
 8491            } => self.render_edit_prediction_diff_popover(
 8492                text_bounds,
 8493                content_origin,
 8494                right_margin,
 8495                editor_snapshot,
 8496                visible_row_range,
 8497                line_layouts,
 8498                line_height,
 8499                scroll_pixel_position,
 8500                newest_selection_head,
 8501                editor_width,
 8502                style,
 8503                edits,
 8504                edit_preview,
 8505                snapshot,
 8506                window,
 8507                cx,
 8508            ),
 8509        }
 8510    }
 8511
 8512    fn render_edit_prediction_modifier_jump_popover(
 8513        &mut self,
 8514        text_bounds: &Bounds<Pixels>,
 8515        content_origin: gpui::Point<Pixels>,
 8516        visible_row_range: Range<DisplayRow>,
 8517        line_layouts: &[LineWithInvisibles],
 8518        line_height: Pixels,
 8519        scroll_pixel_position: gpui::Point<Pixels>,
 8520        newest_selection_head: Option<DisplayPoint>,
 8521        target_display_point: DisplayPoint,
 8522        window: &mut Window,
 8523        cx: &mut App,
 8524    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8525        let scrolled_content_origin =
 8526            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8527
 8528        const SCROLL_PADDING_Y: Pixels = px(12.);
 8529
 8530        if target_display_point.row() < visible_row_range.start {
 8531            return self.render_edit_prediction_scroll_popover(
 8532                |_| SCROLL_PADDING_Y,
 8533                IconName::ArrowUp,
 8534                visible_row_range,
 8535                line_layouts,
 8536                newest_selection_head,
 8537                scrolled_content_origin,
 8538                window,
 8539                cx,
 8540            );
 8541        } else if target_display_point.row() >= visible_row_range.end {
 8542            return self.render_edit_prediction_scroll_popover(
 8543                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8544                IconName::ArrowDown,
 8545                visible_row_range,
 8546                line_layouts,
 8547                newest_selection_head,
 8548                scrolled_content_origin,
 8549                window,
 8550                cx,
 8551            );
 8552        }
 8553
 8554        const POLE_WIDTH: Pixels = px(2.);
 8555
 8556        let line_layout =
 8557            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8558        let target_column = target_display_point.column() as usize;
 8559
 8560        let target_x = line_layout.x_for_index(target_column);
 8561        let target_y =
 8562            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8563
 8564        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8565
 8566        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8567        border_color.l += 0.001;
 8568
 8569        let mut element = v_flex()
 8570            .items_end()
 8571            .when(flag_on_right, |el| el.items_start())
 8572            .child(if flag_on_right {
 8573                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8574                    .rounded_bl(px(0.))
 8575                    .rounded_tl(px(0.))
 8576                    .border_l_2()
 8577                    .border_color(border_color)
 8578            } else {
 8579                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8580                    .rounded_br(px(0.))
 8581                    .rounded_tr(px(0.))
 8582                    .border_r_2()
 8583                    .border_color(border_color)
 8584            })
 8585            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8586            .into_any();
 8587
 8588        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8589
 8590        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8591            - point(
 8592                if flag_on_right {
 8593                    POLE_WIDTH
 8594                } else {
 8595                    size.width - POLE_WIDTH
 8596                },
 8597                size.height - line_height,
 8598            );
 8599
 8600        origin.x = origin.x.max(content_origin.x);
 8601
 8602        element.prepaint_at(origin, window, cx);
 8603
 8604        Some((element, origin))
 8605    }
 8606
 8607    fn render_edit_prediction_scroll_popover(
 8608        &mut self,
 8609        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8610        scroll_icon: IconName,
 8611        visible_row_range: Range<DisplayRow>,
 8612        line_layouts: &[LineWithInvisibles],
 8613        newest_selection_head: Option<DisplayPoint>,
 8614        scrolled_content_origin: gpui::Point<Pixels>,
 8615        window: &mut Window,
 8616        cx: &mut App,
 8617    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8618        let mut element = self
 8619            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8620            .into_any();
 8621
 8622        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8623
 8624        let cursor = newest_selection_head?;
 8625        let cursor_row_layout =
 8626            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8627        let cursor_column = cursor.column() as usize;
 8628
 8629        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8630
 8631        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8632
 8633        element.prepaint_at(origin, window, cx);
 8634        Some((element, origin))
 8635    }
 8636
 8637    fn render_edit_prediction_eager_jump_popover(
 8638        &mut self,
 8639        text_bounds: &Bounds<Pixels>,
 8640        content_origin: gpui::Point<Pixels>,
 8641        editor_snapshot: &EditorSnapshot,
 8642        visible_row_range: Range<DisplayRow>,
 8643        scroll_top: f32,
 8644        scroll_bottom: f32,
 8645        line_height: Pixels,
 8646        scroll_pixel_position: gpui::Point<Pixels>,
 8647        target_display_point: DisplayPoint,
 8648        editor_width: Pixels,
 8649        window: &mut Window,
 8650        cx: &mut App,
 8651    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8652        if target_display_point.row().as_f32() < scroll_top {
 8653            let mut element = self
 8654                .render_edit_prediction_line_popover(
 8655                    "Jump to Edit",
 8656                    Some(IconName::ArrowUp),
 8657                    window,
 8658                    cx,
 8659                )?
 8660                .into_any();
 8661
 8662            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8663            let offset = point(
 8664                (text_bounds.size.width - size.width) / 2.,
 8665                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8666            );
 8667
 8668            let origin = text_bounds.origin + offset;
 8669            element.prepaint_at(origin, window, cx);
 8670            Some((element, origin))
 8671        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8672            let mut element = self
 8673                .render_edit_prediction_line_popover(
 8674                    "Jump to Edit",
 8675                    Some(IconName::ArrowDown),
 8676                    window,
 8677                    cx,
 8678                )?
 8679                .into_any();
 8680
 8681            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8682            let offset = point(
 8683                (text_bounds.size.width - size.width) / 2.,
 8684                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8685            );
 8686
 8687            let origin = text_bounds.origin + offset;
 8688            element.prepaint_at(origin, window, cx);
 8689            Some((element, origin))
 8690        } else {
 8691            self.render_edit_prediction_end_of_line_popover(
 8692                "Jump to Edit",
 8693                editor_snapshot,
 8694                visible_row_range,
 8695                target_display_point,
 8696                line_height,
 8697                scroll_pixel_position,
 8698                content_origin,
 8699                editor_width,
 8700                window,
 8701                cx,
 8702            )
 8703        }
 8704    }
 8705
 8706    fn render_edit_prediction_end_of_line_popover(
 8707        self: &mut Editor,
 8708        label: &'static str,
 8709        editor_snapshot: &EditorSnapshot,
 8710        visible_row_range: Range<DisplayRow>,
 8711        target_display_point: DisplayPoint,
 8712        line_height: Pixels,
 8713        scroll_pixel_position: gpui::Point<Pixels>,
 8714        content_origin: gpui::Point<Pixels>,
 8715        editor_width: Pixels,
 8716        window: &mut Window,
 8717        cx: &mut App,
 8718    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8719        let target_line_end = DisplayPoint::new(
 8720            target_display_point.row(),
 8721            editor_snapshot.line_len(target_display_point.row()),
 8722        );
 8723
 8724        let mut element = self
 8725            .render_edit_prediction_line_popover(label, None, window, cx)?
 8726            .into_any();
 8727
 8728        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8729
 8730        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8731
 8732        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8733        let mut origin = start_point
 8734            + line_origin
 8735            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8736        origin.x = origin.x.max(content_origin.x);
 8737
 8738        let max_x = content_origin.x + editor_width - size.width;
 8739
 8740        if origin.x > max_x {
 8741            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8742
 8743            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8744                origin.y += offset;
 8745                IconName::ArrowUp
 8746            } else {
 8747                origin.y -= offset;
 8748                IconName::ArrowDown
 8749            };
 8750
 8751            element = self
 8752                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8753                .into_any();
 8754
 8755            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8756
 8757            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8758        }
 8759
 8760        element.prepaint_at(origin, window, cx);
 8761        Some((element, origin))
 8762    }
 8763
 8764    fn render_edit_prediction_diff_popover(
 8765        self: &Editor,
 8766        text_bounds: &Bounds<Pixels>,
 8767        content_origin: gpui::Point<Pixels>,
 8768        right_margin: Pixels,
 8769        editor_snapshot: &EditorSnapshot,
 8770        visible_row_range: Range<DisplayRow>,
 8771        line_layouts: &[LineWithInvisibles],
 8772        line_height: Pixels,
 8773        scroll_pixel_position: gpui::Point<Pixels>,
 8774        newest_selection_head: Option<DisplayPoint>,
 8775        editor_width: Pixels,
 8776        style: &EditorStyle,
 8777        edits: &Vec<(Range<Anchor>, String)>,
 8778        edit_preview: &Option<language::EditPreview>,
 8779        snapshot: &language::BufferSnapshot,
 8780        window: &mut Window,
 8781        cx: &mut App,
 8782    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8783        let edit_start = edits
 8784            .first()
 8785            .unwrap()
 8786            .0
 8787            .start
 8788            .to_display_point(editor_snapshot);
 8789        let edit_end = edits
 8790            .last()
 8791            .unwrap()
 8792            .0
 8793            .end
 8794            .to_display_point(editor_snapshot);
 8795
 8796        let is_visible = visible_row_range.contains(&edit_start.row())
 8797            || visible_row_range.contains(&edit_end.row());
 8798        if !is_visible {
 8799            return None;
 8800        }
 8801
 8802        let highlighted_edits =
 8803            crate::edit_prediction_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8804
 8805        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8806        let line_count = highlighted_edits.text.lines().count();
 8807
 8808        const BORDER_WIDTH: Pixels = px(1.);
 8809
 8810        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8811        let has_keybind = keybind.is_some();
 8812
 8813        let mut element = h_flex()
 8814            .items_start()
 8815            .child(
 8816                h_flex()
 8817                    .bg(cx.theme().colors().editor_background)
 8818                    .border(BORDER_WIDTH)
 8819                    .shadow_xs()
 8820                    .border_color(cx.theme().colors().border)
 8821                    .rounded_l_lg()
 8822                    .when(line_count > 1, |el| el.rounded_br_lg())
 8823                    .pr_1()
 8824                    .child(styled_text),
 8825            )
 8826            .child(
 8827                h_flex()
 8828                    .h(line_height + BORDER_WIDTH * 2.)
 8829                    .px_1p5()
 8830                    .gap_1()
 8831                    // Workaround: For some reason, there's a gap if we don't do this
 8832                    .ml(-BORDER_WIDTH)
 8833                    .shadow(vec![gpui::BoxShadow {
 8834                        color: gpui::black().opacity(0.05),
 8835                        offset: point(px(1.), px(1.)),
 8836                        blur_radius: px(2.),
 8837                        spread_radius: px(0.),
 8838                    }])
 8839                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8840                    .border(BORDER_WIDTH)
 8841                    .border_color(cx.theme().colors().border)
 8842                    .rounded_r_lg()
 8843                    .id("edit_prediction_diff_popover_keybind")
 8844                    .when(!has_keybind, |el| {
 8845                        let status_colors = cx.theme().status();
 8846
 8847                        el.bg(status_colors.error_background)
 8848                            .border_color(status_colors.error.opacity(0.6))
 8849                            .child(Icon::new(IconName::Info).color(Color::Error))
 8850                            .cursor_default()
 8851                            .hoverable_tooltip(move |_window, cx| {
 8852                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8853                            })
 8854                    })
 8855                    .children(keybind),
 8856            )
 8857            .into_any();
 8858
 8859        let longest_row =
 8860            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8861        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8862            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8863        } else {
 8864            layout_line(
 8865                longest_row,
 8866                editor_snapshot,
 8867                style,
 8868                editor_width,
 8869                |_| false,
 8870                window,
 8871                cx,
 8872            )
 8873            .width
 8874        };
 8875
 8876        let viewport_bounds =
 8877            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8878                right: -right_margin,
 8879                ..Default::default()
 8880            });
 8881
 8882        let x_after_longest =
 8883            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8884                - scroll_pixel_position.x;
 8885
 8886        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8887
 8888        // Fully visible if it can be displayed within the window (allow overlapping other
 8889        // panes). However, this is only allowed if the popover starts within text_bounds.
 8890        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8891            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8892
 8893        let mut origin = if can_position_to_the_right {
 8894            point(
 8895                x_after_longest,
 8896                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8897                    - scroll_pixel_position.y,
 8898            )
 8899        } else {
 8900            let cursor_row = newest_selection_head.map(|head| head.row());
 8901            let above_edit = edit_start
 8902                .row()
 8903                .0
 8904                .checked_sub(line_count as u32)
 8905                .map(DisplayRow);
 8906            let below_edit = Some(edit_end.row() + 1);
 8907            let above_cursor =
 8908                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8909            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8910
 8911            // Place the edit popover adjacent to the edit if there is a location
 8912            // available that is onscreen and does not obscure the cursor. Otherwise,
 8913            // place it adjacent to the cursor.
 8914            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8915                .into_iter()
 8916                .flatten()
 8917                .find(|&start_row| {
 8918                    let end_row = start_row + line_count as u32;
 8919                    visible_row_range.contains(&start_row)
 8920                        && visible_row_range.contains(&end_row)
 8921                        && cursor_row.map_or(true, |cursor_row| {
 8922                            !((start_row..end_row).contains(&cursor_row))
 8923                        })
 8924                })?;
 8925
 8926            content_origin
 8927                + point(
 8928                    -scroll_pixel_position.x,
 8929                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8930                )
 8931        };
 8932
 8933        origin.x -= BORDER_WIDTH;
 8934
 8935        window.defer_draw(element, origin, 1);
 8936
 8937        // Do not return an element, since it will already be drawn due to defer_draw.
 8938        None
 8939    }
 8940
 8941    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8942        px(30.)
 8943    }
 8944
 8945    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8946        if self.read_only(cx) {
 8947            cx.theme().players().read_only()
 8948        } else {
 8949            self.style.as_ref().unwrap().local_player
 8950        }
 8951    }
 8952
 8953    fn render_edit_prediction_accept_keybind(
 8954        &self,
 8955        window: &mut Window,
 8956        cx: &App,
 8957    ) -> Option<AnyElement> {
 8958        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8959        let accept_keystroke = accept_binding.keystroke()?;
 8960
 8961        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8962
 8963        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8964            Color::Accent
 8965        } else {
 8966            Color::Muted
 8967        };
 8968
 8969        h_flex()
 8970            .px_0p5()
 8971            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8972            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8973            .text_size(TextSize::XSmall.rems(cx))
 8974            .child(h_flex().children(ui::render_modifiers(
 8975                &accept_keystroke.modifiers,
 8976                PlatformStyle::platform(),
 8977                Some(modifiers_color),
 8978                Some(IconSize::XSmall.rems().into()),
 8979                true,
 8980            )))
 8981            .when(is_platform_style_mac, |parent| {
 8982                parent.child(accept_keystroke.key.clone())
 8983            })
 8984            .when(!is_platform_style_mac, |parent| {
 8985                parent.child(
 8986                    Key::new(
 8987                        util::capitalize(&accept_keystroke.key),
 8988                        Some(Color::Default),
 8989                    )
 8990                    .size(Some(IconSize::XSmall.rems().into())),
 8991                )
 8992            })
 8993            .into_any()
 8994            .into()
 8995    }
 8996
 8997    fn render_edit_prediction_line_popover(
 8998        &self,
 8999        label: impl Into<SharedString>,
 9000        icon: Option<IconName>,
 9001        window: &mut Window,
 9002        cx: &App,
 9003    ) -> Option<Stateful<Div>> {
 9004        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9005
 9006        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9007        let has_keybind = keybind.is_some();
 9008
 9009        let result = h_flex()
 9010            .id("ep-line-popover")
 9011            .py_0p5()
 9012            .pl_1()
 9013            .pr(padding_right)
 9014            .gap_1()
 9015            .rounded_md()
 9016            .border_1()
 9017            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9018            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9019            .shadow_xs()
 9020            .when(!has_keybind, |el| {
 9021                let status_colors = cx.theme().status();
 9022
 9023                el.bg(status_colors.error_background)
 9024                    .border_color(status_colors.error.opacity(0.6))
 9025                    .pl_2()
 9026                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9027                    .cursor_default()
 9028                    .hoverable_tooltip(move |_window, cx| {
 9029                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9030                    })
 9031            })
 9032            .children(keybind)
 9033            .child(
 9034                Label::new(label)
 9035                    .size(LabelSize::Small)
 9036                    .when(!has_keybind, |el| {
 9037                        el.color(cx.theme().status().error.into()).strikethrough()
 9038                    }),
 9039            )
 9040            .when(!has_keybind, |el| {
 9041                el.child(
 9042                    h_flex().ml_1().child(
 9043                        Icon::new(IconName::Info)
 9044                            .size(IconSize::Small)
 9045                            .color(cx.theme().status().error.into()),
 9046                    ),
 9047                )
 9048            })
 9049            .when_some(icon, |element, icon| {
 9050                element.child(
 9051                    div()
 9052                        .mt(px(1.5))
 9053                        .child(Icon::new(icon).size(IconSize::Small)),
 9054                )
 9055            });
 9056
 9057        Some(result)
 9058    }
 9059
 9060    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9061        let accent_color = cx.theme().colors().text_accent;
 9062        let editor_bg_color = cx.theme().colors().editor_background;
 9063        editor_bg_color.blend(accent_color.opacity(0.1))
 9064    }
 9065
 9066    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9067        let accent_color = cx.theme().colors().text_accent;
 9068        let editor_bg_color = cx.theme().colors().editor_background;
 9069        editor_bg_color.blend(accent_color.opacity(0.6))
 9070    }
 9071
 9072    fn render_edit_prediction_cursor_popover(
 9073        &self,
 9074        min_width: Pixels,
 9075        max_width: Pixels,
 9076        cursor_point: Point,
 9077        style: &EditorStyle,
 9078        accept_keystroke: Option<&gpui::Keystroke>,
 9079        _window: &Window,
 9080        cx: &mut Context<Editor>,
 9081    ) -> Option<AnyElement> {
 9082        let provider = self.edit_prediction_provider.as_ref()?;
 9083
 9084        if provider.provider.needs_terms_acceptance(cx) {
 9085            return Some(
 9086                h_flex()
 9087                    .min_w(min_width)
 9088                    .flex_1()
 9089                    .px_2()
 9090                    .py_1()
 9091                    .gap_3()
 9092                    .elevation_2(cx)
 9093                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 9094                    .id("accept-terms")
 9095                    .cursor_pointer()
 9096                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 9097                    .on_click(cx.listener(|this, _event, window, cx| {
 9098                        cx.stop_propagation();
 9099                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 9100                        window.dispatch_action(
 9101                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 9102                            cx,
 9103                        );
 9104                    }))
 9105                    .child(
 9106                        h_flex()
 9107                            .flex_1()
 9108                            .gap_2()
 9109                            .child(Icon::new(IconName::ZedPredict))
 9110                            .child(Label::new("Accept Terms of Service"))
 9111                            .child(div().w_full())
 9112                            .child(
 9113                                Icon::new(IconName::ArrowUpRight)
 9114                                    .color(Color::Muted)
 9115                                    .size(IconSize::Small),
 9116                            )
 9117                            .into_any_element(),
 9118                    )
 9119                    .into_any(),
 9120            );
 9121        }
 9122
 9123        let is_refreshing = provider.provider.is_refreshing(cx);
 9124
 9125        fn pending_completion_container() -> Div {
 9126            h_flex()
 9127                .h_full()
 9128                .flex_1()
 9129                .gap_2()
 9130                .child(Icon::new(IconName::ZedPredict))
 9131        }
 9132
 9133        let completion = match &self.active_edit_prediction {
 9134            Some(prediction) => {
 9135                if !self.has_visible_completions_menu() {
 9136                    const RADIUS: Pixels = px(6.);
 9137                    const BORDER_WIDTH: Pixels = px(1.);
 9138
 9139                    return Some(
 9140                        h_flex()
 9141                            .elevation_2(cx)
 9142                            .border(BORDER_WIDTH)
 9143                            .border_color(cx.theme().colors().border)
 9144                            .when(accept_keystroke.is_none(), |el| {
 9145                                el.border_color(cx.theme().status().error)
 9146                            })
 9147                            .rounded(RADIUS)
 9148                            .rounded_tl(px(0.))
 9149                            .overflow_hidden()
 9150                            .child(div().px_1p5().child(match &prediction.completion {
 9151                                EditPrediction::Move { target, snapshot } => {
 9152                                    use text::ToPoint as _;
 9153                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 9154                                    {
 9155                                        Icon::new(IconName::ZedPredictDown)
 9156                                    } else {
 9157                                        Icon::new(IconName::ZedPredictUp)
 9158                                    }
 9159                                }
 9160                                EditPrediction::Edit { .. } => Icon::new(IconName::ZedPredict),
 9161                            }))
 9162                            .child(
 9163                                h_flex()
 9164                                    .gap_1()
 9165                                    .py_1()
 9166                                    .px_2()
 9167                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9168                                    .border_l_1()
 9169                                    .border_color(cx.theme().colors().border)
 9170                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9171                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9172                                        el.child(
 9173                                            Label::new("Hold")
 9174                                                .size(LabelSize::Small)
 9175                                                .when(accept_keystroke.is_none(), |el| {
 9176                                                    el.strikethrough()
 9177                                                })
 9178                                                .line_height_style(LineHeightStyle::UiLabel),
 9179                                        )
 9180                                    })
 9181                                    .id("edit_prediction_cursor_popover_keybind")
 9182                                    .when(accept_keystroke.is_none(), |el| {
 9183                                        let status_colors = cx.theme().status();
 9184
 9185                                        el.bg(status_colors.error_background)
 9186                                            .border_color(status_colors.error.opacity(0.6))
 9187                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9188                                            .cursor_default()
 9189                                            .hoverable_tooltip(move |_window, cx| {
 9190                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9191                                                    .into()
 9192                                            })
 9193                                    })
 9194                                    .when_some(
 9195                                        accept_keystroke.as_ref(),
 9196                                        |el, accept_keystroke| {
 9197                                            el.child(h_flex().children(ui::render_modifiers(
 9198                                                &accept_keystroke.modifiers,
 9199                                                PlatformStyle::platform(),
 9200                                                Some(Color::Default),
 9201                                                Some(IconSize::XSmall.rems().into()),
 9202                                                false,
 9203                                            )))
 9204                                        },
 9205                                    ),
 9206                            )
 9207                            .into_any(),
 9208                    );
 9209                }
 9210
 9211                self.render_edit_prediction_cursor_popover_preview(
 9212                    prediction,
 9213                    cursor_point,
 9214                    style,
 9215                    cx,
 9216                )?
 9217            }
 9218
 9219            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9220                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9221                    stale_completion,
 9222                    cursor_point,
 9223                    style,
 9224                    cx,
 9225                )?,
 9226
 9227                None => {
 9228                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 9229                }
 9230            },
 9231
 9232            None => pending_completion_container().child(Label::new("No Prediction")),
 9233        };
 9234
 9235        let completion = if is_refreshing {
 9236            completion
 9237                .with_animation(
 9238                    "loading-completion",
 9239                    Animation::new(Duration::from_secs(2))
 9240                        .repeat()
 9241                        .with_easing(pulsating_between(0.4, 0.8)),
 9242                    |label, delta| label.opacity(delta),
 9243                )
 9244                .into_any_element()
 9245        } else {
 9246            completion.into_any_element()
 9247        };
 9248
 9249        let has_completion = self.active_edit_prediction.is_some();
 9250
 9251        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9252        Some(
 9253            h_flex()
 9254                .min_w(min_width)
 9255                .max_w(max_width)
 9256                .flex_1()
 9257                .elevation_2(cx)
 9258                .border_color(cx.theme().colors().border)
 9259                .child(
 9260                    div()
 9261                        .flex_1()
 9262                        .py_1()
 9263                        .px_2()
 9264                        .overflow_hidden()
 9265                        .child(completion),
 9266                )
 9267                .when_some(accept_keystroke, |el, accept_keystroke| {
 9268                    if !accept_keystroke.modifiers.modified() {
 9269                        return el;
 9270                    }
 9271
 9272                    el.child(
 9273                        h_flex()
 9274                            .h_full()
 9275                            .border_l_1()
 9276                            .rounded_r_lg()
 9277                            .border_color(cx.theme().colors().border)
 9278                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9279                            .gap_1()
 9280                            .py_1()
 9281                            .px_2()
 9282                            .child(
 9283                                h_flex()
 9284                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9285                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9286                                    .child(h_flex().children(ui::render_modifiers(
 9287                                        &accept_keystroke.modifiers,
 9288                                        PlatformStyle::platform(),
 9289                                        Some(if !has_completion {
 9290                                            Color::Muted
 9291                                        } else {
 9292                                            Color::Default
 9293                                        }),
 9294                                        None,
 9295                                        false,
 9296                                    ))),
 9297                            )
 9298                            .child(Label::new("Preview").into_any_element())
 9299                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9300                    )
 9301                })
 9302                .into_any(),
 9303        )
 9304    }
 9305
 9306    fn render_edit_prediction_cursor_popover_preview(
 9307        &self,
 9308        completion: &EditPredictionState,
 9309        cursor_point: Point,
 9310        style: &EditorStyle,
 9311        cx: &mut Context<Editor>,
 9312    ) -> Option<Div> {
 9313        use text::ToPoint as _;
 9314
 9315        fn render_relative_row_jump(
 9316            prefix: impl Into<String>,
 9317            current_row: u32,
 9318            target_row: u32,
 9319        ) -> Div {
 9320            let (row_diff, arrow) = if target_row < current_row {
 9321                (current_row - target_row, IconName::ArrowUp)
 9322            } else {
 9323                (target_row - current_row, IconName::ArrowDown)
 9324            };
 9325
 9326            h_flex()
 9327                .child(
 9328                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9329                        .color(Color::Muted)
 9330                        .size(LabelSize::Small),
 9331                )
 9332                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9333        }
 9334
 9335        match &completion.completion {
 9336            EditPrediction::Move {
 9337                target, snapshot, ..
 9338            } => Some(
 9339                h_flex()
 9340                    .px_2()
 9341                    .gap_2()
 9342                    .flex_1()
 9343                    .child(
 9344                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9345                            Icon::new(IconName::ZedPredictDown)
 9346                        } else {
 9347                            Icon::new(IconName::ZedPredictUp)
 9348                        },
 9349                    )
 9350                    .child(Label::new("Jump to Edit")),
 9351            ),
 9352
 9353            EditPrediction::Edit {
 9354                edits,
 9355                edit_preview,
 9356                snapshot,
 9357                display_mode: _,
 9358            } => {
 9359                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9360
 9361                let (highlighted_edits, has_more_lines) = crate::edit_prediction_edit_text(
 9362                    &snapshot,
 9363                    &edits,
 9364                    edit_preview.as_ref()?,
 9365                    true,
 9366                    cx,
 9367                )
 9368                .first_line_preview();
 9369
 9370                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9371                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9372
 9373                let preview = h_flex()
 9374                    .gap_1()
 9375                    .min_w_16()
 9376                    .child(styled_text)
 9377                    .when(has_more_lines, |parent| parent.child(""));
 9378
 9379                let left = if first_edit_row != cursor_point.row {
 9380                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9381                        .into_any_element()
 9382                } else {
 9383                    Icon::new(IconName::ZedPredict).into_any_element()
 9384                };
 9385
 9386                Some(
 9387                    h_flex()
 9388                        .h_full()
 9389                        .flex_1()
 9390                        .gap_2()
 9391                        .pr_1()
 9392                        .overflow_x_hidden()
 9393                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9394                        .child(left)
 9395                        .child(preview),
 9396                )
 9397            }
 9398        }
 9399    }
 9400
 9401    pub fn render_context_menu(
 9402        &self,
 9403        style: &EditorStyle,
 9404        max_height_in_lines: u32,
 9405        window: &mut Window,
 9406        cx: &mut Context<Editor>,
 9407    ) -> Option<AnyElement> {
 9408        let menu = self.context_menu.borrow();
 9409        let menu = menu.as_ref()?;
 9410        if !menu.visible() {
 9411            return None;
 9412        };
 9413        Some(menu.render(style, max_height_in_lines, window, cx))
 9414    }
 9415
 9416    fn render_context_menu_aside(
 9417        &mut self,
 9418        max_size: Size<Pixels>,
 9419        window: &mut Window,
 9420        cx: &mut Context<Editor>,
 9421    ) -> Option<AnyElement> {
 9422        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9423            if menu.visible() {
 9424                menu.render_aside(max_size, window, cx)
 9425            } else {
 9426                None
 9427            }
 9428        })
 9429    }
 9430
 9431    fn hide_context_menu(
 9432        &mut self,
 9433        window: &mut Window,
 9434        cx: &mut Context<Self>,
 9435    ) -> Option<CodeContextMenu> {
 9436        cx.notify();
 9437        self.completion_tasks.clear();
 9438        let context_menu = self.context_menu.borrow_mut().take();
 9439        self.stale_edit_prediction_in_menu.take();
 9440        self.update_visible_edit_prediction(window, cx);
 9441        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9442            if let Some(completion_provider) = &self.completion_provider {
 9443                completion_provider.selection_changed(None, window, cx);
 9444            }
 9445        }
 9446        context_menu
 9447    }
 9448
 9449    fn show_snippet_choices(
 9450        &mut self,
 9451        choices: &Vec<String>,
 9452        selection: Range<Anchor>,
 9453        cx: &mut Context<Self>,
 9454    ) {
 9455        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9456            (Some(a), Some(b)) if a == b => a,
 9457            _ => {
 9458                log::error!("expected anchor range to have matching buffer IDs");
 9459                return;
 9460            }
 9461        };
 9462        let multi_buffer = self.buffer().read(cx);
 9463        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9464            return;
 9465        };
 9466
 9467        let id = post_inc(&mut self.next_completion_id);
 9468        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9469        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9470            CompletionsMenu::new_snippet_choices(
 9471                id,
 9472                true,
 9473                choices,
 9474                selection,
 9475                buffer,
 9476                snippet_sort_order,
 9477            ),
 9478        ));
 9479    }
 9480
 9481    pub fn insert_snippet(
 9482        &mut self,
 9483        insertion_ranges: &[Range<usize>],
 9484        snippet: Snippet,
 9485        window: &mut Window,
 9486        cx: &mut Context<Self>,
 9487    ) -> Result<()> {
 9488        struct Tabstop<T> {
 9489            is_end_tabstop: bool,
 9490            ranges: Vec<Range<T>>,
 9491            choices: Option<Vec<String>>,
 9492        }
 9493
 9494        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9495            let snippet_text: Arc<str> = snippet.text.clone().into();
 9496            let edits = insertion_ranges
 9497                .iter()
 9498                .cloned()
 9499                .map(|range| (range, snippet_text.clone()));
 9500            let autoindent_mode = AutoindentMode::Block {
 9501                original_indent_columns: Vec::new(),
 9502            };
 9503            buffer.edit(edits, Some(autoindent_mode), cx);
 9504
 9505            let snapshot = &*buffer.read(cx);
 9506            let snippet = &snippet;
 9507            snippet
 9508                .tabstops
 9509                .iter()
 9510                .map(|tabstop| {
 9511                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9512                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9513                    });
 9514                    let mut tabstop_ranges = tabstop
 9515                        .ranges
 9516                        .iter()
 9517                        .flat_map(|tabstop_range| {
 9518                            let mut delta = 0_isize;
 9519                            insertion_ranges.iter().map(move |insertion_range| {
 9520                                let insertion_start = insertion_range.start as isize + delta;
 9521                                delta +=
 9522                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9523
 9524                                let start = ((insertion_start + tabstop_range.start) as usize)
 9525                                    .min(snapshot.len());
 9526                                let end = ((insertion_start + tabstop_range.end) as usize)
 9527                                    .min(snapshot.len());
 9528                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9529                            })
 9530                        })
 9531                        .collect::<Vec<_>>();
 9532                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9533
 9534                    Tabstop {
 9535                        is_end_tabstop,
 9536                        ranges: tabstop_ranges,
 9537                        choices: tabstop.choices.clone(),
 9538                    }
 9539                })
 9540                .collect::<Vec<_>>()
 9541        });
 9542        if let Some(tabstop) = tabstops.first() {
 9543            self.change_selections(Default::default(), window, cx, |s| {
 9544                // Reverse order so that the first range is the newest created selection.
 9545                // Completions will use it and autoscroll will prioritize it.
 9546                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9547            });
 9548
 9549            if let Some(choices) = &tabstop.choices {
 9550                if let Some(selection) = tabstop.ranges.first() {
 9551                    self.show_snippet_choices(choices, selection.clone(), cx)
 9552                }
 9553            }
 9554
 9555            // If we're already at the last tabstop and it's at the end of the snippet,
 9556            // we're done, we don't need to keep the state around.
 9557            if !tabstop.is_end_tabstop {
 9558                let choices = tabstops
 9559                    .iter()
 9560                    .map(|tabstop| tabstop.choices.clone())
 9561                    .collect();
 9562
 9563                let ranges = tabstops
 9564                    .into_iter()
 9565                    .map(|tabstop| tabstop.ranges)
 9566                    .collect::<Vec<_>>();
 9567
 9568                self.snippet_stack.push(SnippetState {
 9569                    active_index: 0,
 9570                    ranges,
 9571                    choices,
 9572                });
 9573            }
 9574
 9575            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9576            if self.autoclose_regions.is_empty() {
 9577                let snapshot = self.buffer.read(cx).snapshot(cx);
 9578                let mut all_selections = self.selections.all::<Point>(cx);
 9579                for selection in &mut all_selections {
 9580                    let selection_head = selection.head();
 9581                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9582                        continue;
 9583                    };
 9584
 9585                    let mut bracket_pair = None;
 9586                    let max_lookup_length = scope
 9587                        .brackets()
 9588                        .map(|(pair, _)| {
 9589                            pair.start
 9590                                .as_str()
 9591                                .chars()
 9592                                .count()
 9593                                .max(pair.end.as_str().chars().count())
 9594                        })
 9595                        .max();
 9596                    if let Some(max_lookup_length) = max_lookup_length {
 9597                        let next_text = snapshot
 9598                            .chars_at(selection_head)
 9599                            .take(max_lookup_length)
 9600                            .collect::<String>();
 9601                        let prev_text = snapshot
 9602                            .reversed_chars_at(selection_head)
 9603                            .take(max_lookup_length)
 9604                            .collect::<String>();
 9605
 9606                        for (pair, enabled) in scope.brackets() {
 9607                            if enabled
 9608                                && pair.close
 9609                                && prev_text.starts_with(pair.start.as_str())
 9610                                && next_text.starts_with(pair.end.as_str())
 9611                            {
 9612                                bracket_pair = Some(pair.clone());
 9613                                break;
 9614                            }
 9615                        }
 9616                    }
 9617
 9618                    if let Some(pair) = bracket_pair {
 9619                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9620                        let autoclose_enabled =
 9621                            self.use_autoclose && snapshot_settings.use_autoclose;
 9622                        if autoclose_enabled {
 9623                            let start = snapshot.anchor_after(selection_head);
 9624                            let end = snapshot.anchor_after(selection_head);
 9625                            self.autoclose_regions.push(AutocloseRegion {
 9626                                selection_id: selection.id,
 9627                                range: start..end,
 9628                                pair,
 9629                            });
 9630                        }
 9631                    }
 9632                }
 9633            }
 9634        }
 9635        Ok(())
 9636    }
 9637
 9638    pub fn move_to_next_snippet_tabstop(
 9639        &mut self,
 9640        window: &mut Window,
 9641        cx: &mut Context<Self>,
 9642    ) -> bool {
 9643        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9644    }
 9645
 9646    pub fn move_to_prev_snippet_tabstop(
 9647        &mut self,
 9648        window: &mut Window,
 9649        cx: &mut Context<Self>,
 9650    ) -> bool {
 9651        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9652    }
 9653
 9654    pub fn move_to_snippet_tabstop(
 9655        &mut self,
 9656        bias: Bias,
 9657        window: &mut Window,
 9658        cx: &mut Context<Self>,
 9659    ) -> bool {
 9660        if let Some(mut snippet) = self.snippet_stack.pop() {
 9661            match bias {
 9662                Bias::Left => {
 9663                    if snippet.active_index > 0 {
 9664                        snippet.active_index -= 1;
 9665                    } else {
 9666                        self.snippet_stack.push(snippet);
 9667                        return false;
 9668                    }
 9669                }
 9670                Bias::Right => {
 9671                    if snippet.active_index + 1 < snippet.ranges.len() {
 9672                        snippet.active_index += 1;
 9673                    } else {
 9674                        self.snippet_stack.push(snippet);
 9675                        return false;
 9676                    }
 9677                }
 9678            }
 9679            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9680                self.change_selections(Default::default(), window, cx, |s| {
 9681                    // Reverse order so that the first range is the newest created selection.
 9682                    // Completions will use it and autoscroll will prioritize it.
 9683                    s.select_ranges(current_ranges.iter().rev().cloned())
 9684                });
 9685
 9686                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9687                    if let Some(selection) = current_ranges.first() {
 9688                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9689                    }
 9690                }
 9691
 9692                // If snippet state is not at the last tabstop, push it back on the stack
 9693                if snippet.active_index + 1 < snippet.ranges.len() {
 9694                    self.snippet_stack.push(snippet);
 9695                }
 9696                return true;
 9697            }
 9698        }
 9699
 9700        false
 9701    }
 9702
 9703    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9704        self.transact(window, cx, |this, window, cx| {
 9705            this.select_all(&SelectAll, window, cx);
 9706            this.insert("", window, cx);
 9707        });
 9708    }
 9709
 9710    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9711        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9712        self.transact(window, cx, |this, window, cx| {
 9713            this.select_autoclose_pair(window, cx);
 9714            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9715            if !this.linked_edit_ranges.is_empty() {
 9716                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9717                let snapshot = this.buffer.read(cx).snapshot(cx);
 9718
 9719                for selection in selections.iter() {
 9720                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9721                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9722                    if selection_start.buffer_id != selection_end.buffer_id {
 9723                        continue;
 9724                    }
 9725                    if let Some(ranges) =
 9726                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9727                    {
 9728                        for (buffer, entries) in ranges {
 9729                            linked_ranges.entry(buffer).or_default().extend(entries);
 9730                        }
 9731                    }
 9732                }
 9733            }
 9734
 9735            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9736            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9737            for selection in &mut selections {
 9738                if selection.is_empty() {
 9739                    let old_head = selection.head();
 9740                    let mut new_head =
 9741                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9742                            .to_point(&display_map);
 9743                    if let Some((buffer, line_buffer_range)) = display_map
 9744                        .buffer_snapshot
 9745                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9746                    {
 9747                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9748                        let indent_len = match indent_size.kind {
 9749                            IndentKind::Space => {
 9750                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9751                            }
 9752                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9753                        };
 9754                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9755                            let indent_len = indent_len.get();
 9756                            new_head = cmp::min(
 9757                                new_head,
 9758                                MultiBufferPoint::new(
 9759                                    old_head.row,
 9760                                    ((old_head.column - 1) / indent_len) * indent_len,
 9761                                ),
 9762                            );
 9763                        }
 9764                    }
 9765
 9766                    selection.set_head(new_head, SelectionGoal::None);
 9767                }
 9768            }
 9769
 9770            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9771            this.insert("", window, cx);
 9772            let empty_str: Arc<str> = Arc::from("");
 9773            for (buffer, edits) in linked_ranges {
 9774                let snapshot = buffer.read(cx).snapshot();
 9775                use text::ToPoint as TP;
 9776
 9777                let edits = edits
 9778                    .into_iter()
 9779                    .map(|range| {
 9780                        let end_point = TP::to_point(&range.end, &snapshot);
 9781                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9782
 9783                        if end_point == start_point {
 9784                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9785                                .saturating_sub(1);
 9786                            start_point =
 9787                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9788                        };
 9789
 9790                        (start_point..end_point, empty_str.clone())
 9791                    })
 9792                    .sorted_by_key(|(range, _)| range.start)
 9793                    .collect::<Vec<_>>();
 9794                buffer.update(cx, |this, cx| {
 9795                    this.edit(edits, None, cx);
 9796                })
 9797            }
 9798            this.refresh_edit_prediction(true, false, window, cx);
 9799            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9800        });
 9801    }
 9802
 9803    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9804        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9805        self.transact(window, cx, |this, window, cx| {
 9806            this.change_selections(Default::default(), window, cx, |s| {
 9807                s.move_with(|map, selection| {
 9808                    if selection.is_empty() {
 9809                        let cursor = movement::right(map, selection.head());
 9810                        selection.end = cursor;
 9811                        selection.reversed = true;
 9812                        selection.goal = SelectionGoal::None;
 9813                    }
 9814                })
 9815            });
 9816            this.insert("", window, cx);
 9817            this.refresh_edit_prediction(true, false, window, cx);
 9818        });
 9819    }
 9820
 9821    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9822        if self.mode.is_single_line() {
 9823            cx.propagate();
 9824            return;
 9825        }
 9826
 9827        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9828        if self.move_to_prev_snippet_tabstop(window, cx) {
 9829            return;
 9830        }
 9831        self.outdent(&Outdent, window, cx);
 9832    }
 9833
 9834    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9835        if self.mode.is_single_line() {
 9836            cx.propagate();
 9837            return;
 9838        }
 9839
 9840        if self.move_to_next_snippet_tabstop(window, cx) {
 9841            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9842            return;
 9843        }
 9844        if self.read_only(cx) {
 9845            return;
 9846        }
 9847        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9848        let mut selections = self.selections.all_adjusted(cx);
 9849        let buffer = self.buffer.read(cx);
 9850        let snapshot = buffer.snapshot(cx);
 9851        let rows_iter = selections.iter().map(|s| s.head().row);
 9852        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9853
 9854        let has_some_cursor_in_whitespace = selections
 9855            .iter()
 9856            .filter(|selection| selection.is_empty())
 9857            .any(|selection| {
 9858                let cursor = selection.head();
 9859                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9860                cursor.column < current_indent.len
 9861            });
 9862
 9863        let mut edits = Vec::new();
 9864        let mut prev_edited_row = 0;
 9865        let mut row_delta = 0;
 9866        for selection in &mut selections {
 9867            if selection.start.row != prev_edited_row {
 9868                row_delta = 0;
 9869            }
 9870            prev_edited_row = selection.end.row;
 9871
 9872            // If the selection is non-empty, then increase the indentation of the selected lines.
 9873            if !selection.is_empty() {
 9874                row_delta =
 9875                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9876                continue;
 9877            }
 9878
 9879            let cursor = selection.head();
 9880            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9881            if let Some(suggested_indent) =
 9882                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9883            {
 9884                // Don't do anything if already at suggested indent
 9885                // and there is any other cursor which is not
 9886                if has_some_cursor_in_whitespace
 9887                    && cursor.column == current_indent.len
 9888                    && current_indent.len == suggested_indent.len
 9889                {
 9890                    continue;
 9891                }
 9892
 9893                // Adjust line and move cursor to suggested indent
 9894                // if cursor is not at suggested indent
 9895                if cursor.column < suggested_indent.len
 9896                    && cursor.column <= current_indent.len
 9897                    && current_indent.len <= suggested_indent.len
 9898                {
 9899                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9900                    selection.end = selection.start;
 9901                    if row_delta == 0 {
 9902                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9903                            cursor.row,
 9904                            current_indent,
 9905                            suggested_indent,
 9906                        ));
 9907                        row_delta = suggested_indent.len - current_indent.len;
 9908                    }
 9909                    continue;
 9910                }
 9911
 9912                // If current indent is more than suggested indent
 9913                // only move cursor to current indent and skip indent
 9914                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9915                    selection.start = Point::new(cursor.row, current_indent.len);
 9916                    selection.end = selection.start;
 9917                    continue;
 9918                }
 9919            }
 9920
 9921            // Otherwise, insert a hard or soft tab.
 9922            let settings = buffer.language_settings_at(cursor, cx);
 9923            let tab_size = if settings.hard_tabs {
 9924                IndentSize::tab()
 9925            } else {
 9926                let tab_size = settings.tab_size.get();
 9927                let indent_remainder = snapshot
 9928                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9929                    .flat_map(str::chars)
 9930                    .fold(row_delta % tab_size, |counter: u32, c| {
 9931                        if c == '\t' {
 9932                            0
 9933                        } else {
 9934                            (counter + 1) % tab_size
 9935                        }
 9936                    });
 9937
 9938                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9939                IndentSize::spaces(chars_to_next_tab_stop)
 9940            };
 9941            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9942            selection.end = selection.start;
 9943            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9944            row_delta += tab_size.len;
 9945        }
 9946
 9947        self.transact(window, cx, |this, window, cx| {
 9948            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9949            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9950            this.refresh_edit_prediction(true, false, window, cx);
 9951        });
 9952    }
 9953
 9954    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9955        if self.read_only(cx) {
 9956            return;
 9957        }
 9958        if self.mode.is_single_line() {
 9959            cx.propagate();
 9960            return;
 9961        }
 9962
 9963        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9964        let mut selections = self.selections.all::<Point>(cx);
 9965        let mut prev_edited_row = 0;
 9966        let mut row_delta = 0;
 9967        let mut edits = Vec::new();
 9968        let buffer = self.buffer.read(cx);
 9969        let snapshot = buffer.snapshot(cx);
 9970        for selection in &mut selections {
 9971            if selection.start.row != prev_edited_row {
 9972                row_delta = 0;
 9973            }
 9974            prev_edited_row = selection.end.row;
 9975
 9976            row_delta =
 9977                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9978        }
 9979
 9980        self.transact(window, cx, |this, window, cx| {
 9981            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9982            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9983        });
 9984    }
 9985
 9986    fn indent_selection(
 9987        buffer: &MultiBuffer,
 9988        snapshot: &MultiBufferSnapshot,
 9989        selection: &mut Selection<Point>,
 9990        edits: &mut Vec<(Range<Point>, String)>,
 9991        delta_for_start_row: u32,
 9992        cx: &App,
 9993    ) -> u32 {
 9994        let settings = buffer.language_settings_at(selection.start, cx);
 9995        let tab_size = settings.tab_size.get();
 9996        let indent_kind = if settings.hard_tabs {
 9997            IndentKind::Tab
 9998        } else {
 9999            IndentKind::Space
10000        };
10001        let mut start_row = selection.start.row;
10002        let mut end_row = selection.end.row + 1;
10003
10004        // If a selection ends at the beginning of a line, don't indent
10005        // that last line.
10006        if selection.end.column == 0 && selection.end.row > selection.start.row {
10007            end_row -= 1;
10008        }
10009
10010        // Avoid re-indenting a row that has already been indented by a
10011        // previous selection, but still update this selection's column
10012        // to reflect that indentation.
10013        if delta_for_start_row > 0 {
10014            start_row += 1;
10015            selection.start.column += delta_for_start_row;
10016            if selection.end.row == selection.start.row {
10017                selection.end.column += delta_for_start_row;
10018            }
10019        }
10020
10021        let mut delta_for_end_row = 0;
10022        let has_multiple_rows = start_row + 1 != end_row;
10023        for row in start_row..end_row {
10024            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10025            let indent_delta = match (current_indent.kind, indent_kind) {
10026                (IndentKind::Space, IndentKind::Space) => {
10027                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10028                    IndentSize::spaces(columns_to_next_tab_stop)
10029                }
10030                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10031                (_, IndentKind::Tab) => IndentSize::tab(),
10032            };
10033
10034            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10035                0
10036            } else {
10037                selection.start.column
10038            };
10039            let row_start = Point::new(row, start);
10040            edits.push((
10041                row_start..row_start,
10042                indent_delta.chars().collect::<String>(),
10043            ));
10044
10045            // Update this selection's endpoints to reflect the indentation.
10046            if row == selection.start.row {
10047                selection.start.column += indent_delta.len;
10048            }
10049            if row == selection.end.row {
10050                selection.end.column += indent_delta.len;
10051                delta_for_end_row = indent_delta.len;
10052            }
10053        }
10054
10055        if selection.start.row == selection.end.row {
10056            delta_for_start_row + delta_for_end_row
10057        } else {
10058            delta_for_end_row
10059        }
10060    }
10061
10062    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10063        if self.read_only(cx) {
10064            return;
10065        }
10066        if self.mode.is_single_line() {
10067            cx.propagate();
10068            return;
10069        }
10070
10071        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10072        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10073        let selections = self.selections.all::<Point>(cx);
10074        let mut deletion_ranges = Vec::new();
10075        let mut last_outdent = None;
10076        {
10077            let buffer = self.buffer.read(cx);
10078            let snapshot = buffer.snapshot(cx);
10079            for selection in &selections {
10080                let settings = buffer.language_settings_at(selection.start, cx);
10081                let tab_size = settings.tab_size.get();
10082                let mut rows = selection.spanned_rows(false, &display_map);
10083
10084                // Avoid re-outdenting a row that has already been outdented by a
10085                // previous selection.
10086                if let Some(last_row) = last_outdent {
10087                    if last_row == rows.start {
10088                        rows.start = rows.start.next_row();
10089                    }
10090                }
10091                let has_multiple_rows = rows.len() > 1;
10092                for row in rows.iter_rows() {
10093                    let indent_size = snapshot.indent_size_for_line(row);
10094                    if indent_size.len > 0 {
10095                        let deletion_len = match indent_size.kind {
10096                            IndentKind::Space => {
10097                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10098                                if columns_to_prev_tab_stop == 0 {
10099                                    tab_size
10100                                } else {
10101                                    columns_to_prev_tab_stop
10102                                }
10103                            }
10104                            IndentKind::Tab => 1,
10105                        };
10106                        let start = if has_multiple_rows
10107                            || deletion_len > selection.start.column
10108                            || indent_size.len < selection.start.column
10109                        {
10110                            0
10111                        } else {
10112                            selection.start.column - deletion_len
10113                        };
10114                        deletion_ranges.push(
10115                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10116                        );
10117                        last_outdent = Some(row);
10118                    }
10119                }
10120            }
10121        }
10122
10123        self.transact(window, cx, |this, window, cx| {
10124            this.buffer.update(cx, |buffer, cx| {
10125                let empty_str: Arc<str> = Arc::default();
10126                buffer.edit(
10127                    deletion_ranges
10128                        .into_iter()
10129                        .map(|range| (range, empty_str.clone())),
10130                    None,
10131                    cx,
10132                );
10133            });
10134            let selections = this.selections.all::<usize>(cx);
10135            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10136        });
10137    }
10138
10139    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10140        if self.read_only(cx) {
10141            return;
10142        }
10143        if self.mode.is_single_line() {
10144            cx.propagate();
10145            return;
10146        }
10147
10148        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10149        let selections = self
10150            .selections
10151            .all::<usize>(cx)
10152            .into_iter()
10153            .map(|s| s.range());
10154
10155        self.transact(window, cx, |this, window, cx| {
10156            this.buffer.update(cx, |buffer, cx| {
10157                buffer.autoindent_ranges(selections, cx);
10158            });
10159            let selections = this.selections.all::<usize>(cx);
10160            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10161        });
10162    }
10163
10164    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10165        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10166        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10167        let selections = self.selections.all::<Point>(cx);
10168
10169        let mut new_cursors = Vec::new();
10170        let mut edit_ranges = Vec::new();
10171        let mut selections = selections.iter().peekable();
10172        while let Some(selection) = selections.next() {
10173            let mut rows = selection.spanned_rows(false, &display_map);
10174            let goal_display_column = selection.head().to_display_point(&display_map).column();
10175
10176            // Accumulate contiguous regions of rows that we want to delete.
10177            while let Some(next_selection) = selections.peek() {
10178                let next_rows = next_selection.spanned_rows(false, &display_map);
10179                if next_rows.start <= rows.end {
10180                    rows.end = next_rows.end;
10181                    selections.next().unwrap();
10182                } else {
10183                    break;
10184                }
10185            }
10186
10187            let buffer = &display_map.buffer_snapshot;
10188            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10189            let edit_end;
10190            let cursor_buffer_row;
10191            if buffer.max_point().row >= rows.end.0 {
10192                // If there's a line after the range, delete the \n from the end of the row range
10193                // and position the cursor on the next line.
10194                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10195                cursor_buffer_row = rows.end;
10196            } else {
10197                // If there isn't a line after the range, delete the \n from the line before the
10198                // start of the row range and position the cursor there.
10199                edit_start = edit_start.saturating_sub(1);
10200                edit_end = buffer.len();
10201                cursor_buffer_row = rows.start.previous_row();
10202            }
10203
10204            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10205            *cursor.column_mut() =
10206                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10207
10208            new_cursors.push((
10209                selection.id,
10210                buffer.anchor_after(cursor.to_point(&display_map)),
10211            ));
10212            edit_ranges.push(edit_start..edit_end);
10213        }
10214
10215        self.transact(window, cx, |this, window, cx| {
10216            let buffer = this.buffer.update(cx, |buffer, cx| {
10217                let empty_str: Arc<str> = Arc::default();
10218                buffer.edit(
10219                    edit_ranges
10220                        .into_iter()
10221                        .map(|range| (range, empty_str.clone())),
10222                    None,
10223                    cx,
10224                );
10225                buffer.snapshot(cx)
10226            });
10227            let new_selections = new_cursors
10228                .into_iter()
10229                .map(|(id, cursor)| {
10230                    let cursor = cursor.to_point(&buffer);
10231                    Selection {
10232                        id,
10233                        start: cursor,
10234                        end: cursor,
10235                        reversed: false,
10236                        goal: SelectionGoal::None,
10237                    }
10238                })
10239                .collect();
10240
10241            this.change_selections(Default::default(), window, cx, |s| {
10242                s.select(new_selections);
10243            });
10244        });
10245    }
10246
10247    pub fn join_lines_impl(
10248        &mut self,
10249        insert_whitespace: bool,
10250        window: &mut Window,
10251        cx: &mut Context<Self>,
10252    ) {
10253        if self.read_only(cx) {
10254            return;
10255        }
10256        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10257        for selection in self.selections.all::<Point>(cx) {
10258            let start = MultiBufferRow(selection.start.row);
10259            // Treat single line selections as if they include the next line. Otherwise this action
10260            // would do nothing for single line selections individual cursors.
10261            let end = if selection.start.row == selection.end.row {
10262                MultiBufferRow(selection.start.row + 1)
10263            } else {
10264                MultiBufferRow(selection.end.row)
10265            };
10266
10267            if let Some(last_row_range) = row_ranges.last_mut() {
10268                if start <= last_row_range.end {
10269                    last_row_range.end = end;
10270                    continue;
10271                }
10272            }
10273            row_ranges.push(start..end);
10274        }
10275
10276        let snapshot = self.buffer.read(cx).snapshot(cx);
10277        let mut cursor_positions = Vec::new();
10278        for row_range in &row_ranges {
10279            let anchor = snapshot.anchor_before(Point::new(
10280                row_range.end.previous_row().0,
10281                snapshot.line_len(row_range.end.previous_row()),
10282            ));
10283            cursor_positions.push(anchor..anchor);
10284        }
10285
10286        self.transact(window, cx, |this, window, cx| {
10287            for row_range in row_ranges.into_iter().rev() {
10288                for row in row_range.iter_rows().rev() {
10289                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10290                    let next_line_row = row.next_row();
10291                    let indent = snapshot.indent_size_for_line(next_line_row);
10292                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10293
10294                    let replace =
10295                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10296                            " "
10297                        } else {
10298                            ""
10299                        };
10300
10301                    this.buffer.update(cx, |buffer, cx| {
10302                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10303                    });
10304                }
10305            }
10306
10307            this.change_selections(Default::default(), window, cx, |s| {
10308                s.select_anchor_ranges(cursor_positions)
10309            });
10310        });
10311    }
10312
10313    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10314        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10315        self.join_lines_impl(true, window, cx);
10316    }
10317
10318    pub fn sort_lines_case_sensitive(
10319        &mut self,
10320        _: &SortLinesCaseSensitive,
10321        window: &mut Window,
10322        cx: &mut Context<Self>,
10323    ) {
10324        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10325    }
10326
10327    pub fn sort_lines_by_length(
10328        &mut self,
10329        _: &SortLinesByLength,
10330        window: &mut Window,
10331        cx: &mut Context<Self>,
10332    ) {
10333        self.manipulate_immutable_lines(window, cx, |lines| {
10334            lines.sort_by_key(|&line| line.chars().count())
10335        })
10336    }
10337
10338    pub fn sort_lines_case_insensitive(
10339        &mut self,
10340        _: &SortLinesCaseInsensitive,
10341        window: &mut Window,
10342        cx: &mut Context<Self>,
10343    ) {
10344        self.manipulate_immutable_lines(window, cx, |lines| {
10345            lines.sort_by_key(|line| line.to_lowercase())
10346        })
10347    }
10348
10349    pub fn unique_lines_case_insensitive(
10350        &mut self,
10351        _: &UniqueLinesCaseInsensitive,
10352        window: &mut Window,
10353        cx: &mut Context<Self>,
10354    ) {
10355        self.manipulate_immutable_lines(window, cx, |lines| {
10356            let mut seen = HashSet::default();
10357            lines.retain(|line| seen.insert(line.to_lowercase()));
10358        })
10359    }
10360
10361    pub fn unique_lines_case_sensitive(
10362        &mut self,
10363        _: &UniqueLinesCaseSensitive,
10364        window: &mut Window,
10365        cx: &mut Context<Self>,
10366    ) {
10367        self.manipulate_immutable_lines(window, cx, |lines| {
10368            let mut seen = HashSet::default();
10369            lines.retain(|line| seen.insert(*line));
10370        })
10371    }
10372
10373    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10374        let Some(project) = self.project.clone() else {
10375            return;
10376        };
10377        self.reload(project, window, cx)
10378            .detach_and_notify_err(window, cx);
10379    }
10380
10381    pub fn restore_file(
10382        &mut self,
10383        _: &::git::RestoreFile,
10384        window: &mut Window,
10385        cx: &mut Context<Self>,
10386    ) {
10387        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10388        let mut buffer_ids = HashSet::default();
10389        let snapshot = self.buffer().read(cx).snapshot(cx);
10390        for selection in self.selections.all::<usize>(cx) {
10391            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10392        }
10393
10394        let buffer = self.buffer().read(cx);
10395        let ranges = buffer_ids
10396            .into_iter()
10397            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10398            .collect::<Vec<_>>();
10399
10400        self.restore_hunks_in_ranges(ranges, window, cx);
10401    }
10402
10403    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10404        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10405        let selections = self
10406            .selections
10407            .all(cx)
10408            .into_iter()
10409            .map(|s| s.range())
10410            .collect();
10411        self.restore_hunks_in_ranges(selections, window, cx);
10412    }
10413
10414    pub fn restore_hunks_in_ranges(
10415        &mut self,
10416        ranges: Vec<Range<Point>>,
10417        window: &mut Window,
10418        cx: &mut Context<Editor>,
10419    ) {
10420        let mut revert_changes = HashMap::default();
10421        let chunk_by = self
10422            .snapshot(window, cx)
10423            .hunks_for_ranges(ranges)
10424            .into_iter()
10425            .chunk_by(|hunk| hunk.buffer_id);
10426        for (buffer_id, hunks) in &chunk_by {
10427            let hunks = hunks.collect::<Vec<_>>();
10428            for hunk in &hunks {
10429                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10430            }
10431            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10432        }
10433        drop(chunk_by);
10434        if !revert_changes.is_empty() {
10435            self.transact(window, cx, |editor, window, cx| {
10436                editor.restore(revert_changes, window, cx);
10437            });
10438        }
10439    }
10440
10441    pub fn open_active_item_in_terminal(
10442        &mut self,
10443        _: &OpenInTerminal,
10444        window: &mut Window,
10445        cx: &mut Context<Self>,
10446    ) {
10447        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10448            let project_path = buffer.read(cx).project_path(cx)?;
10449            let project = self.project.as_ref()?.read(cx);
10450            let entry = project.entry_for_path(&project_path, cx)?;
10451            let parent = match &entry.canonical_path {
10452                Some(canonical_path) => canonical_path.to_path_buf(),
10453                None => project.absolute_path(&project_path, cx)?,
10454            }
10455            .parent()?
10456            .to_path_buf();
10457            Some(parent)
10458        }) {
10459            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10460        }
10461    }
10462
10463    fn set_breakpoint_context_menu(
10464        &mut self,
10465        display_row: DisplayRow,
10466        position: Option<Anchor>,
10467        clicked_point: gpui::Point<Pixels>,
10468        window: &mut Window,
10469        cx: &mut Context<Self>,
10470    ) {
10471        let source = self
10472            .buffer
10473            .read(cx)
10474            .snapshot(cx)
10475            .anchor_before(Point::new(display_row.0, 0u32));
10476
10477        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10478
10479        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10480            self,
10481            source,
10482            clicked_point,
10483            context_menu,
10484            window,
10485            cx,
10486        );
10487    }
10488
10489    fn add_edit_breakpoint_block(
10490        &mut self,
10491        anchor: Anchor,
10492        breakpoint: &Breakpoint,
10493        edit_action: BreakpointPromptEditAction,
10494        window: &mut Window,
10495        cx: &mut Context<Self>,
10496    ) {
10497        let weak_editor = cx.weak_entity();
10498        let bp_prompt = cx.new(|cx| {
10499            BreakpointPromptEditor::new(
10500                weak_editor,
10501                anchor,
10502                breakpoint.clone(),
10503                edit_action,
10504                window,
10505                cx,
10506            )
10507        });
10508
10509        let height = bp_prompt.update(cx, |this, cx| {
10510            this.prompt
10511                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10512        });
10513        let cloned_prompt = bp_prompt.clone();
10514        let blocks = vec![BlockProperties {
10515            style: BlockStyle::Sticky,
10516            placement: BlockPlacement::Above(anchor),
10517            height: Some(height),
10518            render: Arc::new(move |cx| {
10519                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10520                cloned_prompt.clone().into_any_element()
10521            }),
10522            priority: 0,
10523        }];
10524
10525        let focus_handle = bp_prompt.focus_handle(cx);
10526        window.focus(&focus_handle);
10527
10528        let block_ids = self.insert_blocks(blocks, None, cx);
10529        bp_prompt.update(cx, |prompt, _| {
10530            prompt.add_block_ids(block_ids);
10531        });
10532    }
10533
10534    pub(crate) fn breakpoint_at_row(
10535        &self,
10536        row: u32,
10537        window: &mut Window,
10538        cx: &mut Context<Self>,
10539    ) -> Option<(Anchor, Breakpoint)> {
10540        let snapshot = self.snapshot(window, cx);
10541        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10542
10543        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10544    }
10545
10546    pub(crate) fn breakpoint_at_anchor(
10547        &self,
10548        breakpoint_position: Anchor,
10549        snapshot: &EditorSnapshot,
10550        cx: &mut Context<Self>,
10551    ) -> Option<(Anchor, Breakpoint)> {
10552        let project = self.project.clone()?;
10553
10554        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10555            snapshot
10556                .buffer_snapshot
10557                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10558        })?;
10559
10560        let enclosing_excerpt = breakpoint_position.excerpt_id;
10561        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10562        let buffer_snapshot = buffer.read(cx).snapshot();
10563
10564        let row = buffer_snapshot
10565            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10566            .row;
10567
10568        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10569        let anchor_end = snapshot
10570            .buffer_snapshot
10571            .anchor_after(Point::new(row, line_len));
10572
10573        let bp = self
10574            .breakpoint_store
10575            .as_ref()?
10576            .read_with(cx, |breakpoint_store, cx| {
10577                breakpoint_store
10578                    .breakpoints(
10579                        &buffer,
10580                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10581                        &buffer_snapshot,
10582                        cx,
10583                    )
10584                    .next()
10585                    .and_then(|(bp, _)| {
10586                        let breakpoint_row = buffer_snapshot
10587                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10588                            .row;
10589
10590                        if breakpoint_row == row {
10591                            snapshot
10592                                .buffer_snapshot
10593                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10594                                .map(|position| (position, bp.bp.clone()))
10595                        } else {
10596                            None
10597                        }
10598                    })
10599            });
10600        bp
10601    }
10602
10603    pub fn edit_log_breakpoint(
10604        &mut self,
10605        _: &EditLogBreakpoint,
10606        window: &mut Window,
10607        cx: &mut Context<Self>,
10608    ) {
10609        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10610            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10611                message: None,
10612                state: BreakpointState::Enabled,
10613                condition: None,
10614                hit_condition: None,
10615            });
10616
10617            self.add_edit_breakpoint_block(
10618                anchor,
10619                &breakpoint,
10620                BreakpointPromptEditAction::Log,
10621                window,
10622                cx,
10623            );
10624        }
10625    }
10626
10627    fn breakpoints_at_cursors(
10628        &self,
10629        window: &mut Window,
10630        cx: &mut Context<Self>,
10631    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10632        let snapshot = self.snapshot(window, cx);
10633        let cursors = self
10634            .selections
10635            .disjoint_anchors()
10636            .into_iter()
10637            .map(|selection| {
10638                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10639
10640                let breakpoint_position = self
10641                    .breakpoint_at_row(cursor_position.row, window, cx)
10642                    .map(|bp| bp.0)
10643                    .unwrap_or_else(|| {
10644                        snapshot
10645                            .display_snapshot
10646                            .buffer_snapshot
10647                            .anchor_after(Point::new(cursor_position.row, 0))
10648                    });
10649
10650                let breakpoint = self
10651                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10652                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10653
10654                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10655            })
10656            // 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.
10657            .collect::<HashMap<Anchor, _>>();
10658
10659        cursors.into_iter().collect()
10660    }
10661
10662    pub fn enable_breakpoint(
10663        &mut self,
10664        _: &crate::actions::EnableBreakpoint,
10665        window: &mut Window,
10666        cx: &mut Context<Self>,
10667    ) {
10668        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10669            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10670                continue;
10671            };
10672            self.edit_breakpoint_at_anchor(
10673                anchor,
10674                breakpoint,
10675                BreakpointEditAction::InvertState,
10676                cx,
10677            );
10678        }
10679    }
10680
10681    pub fn disable_breakpoint(
10682        &mut self,
10683        _: &crate::actions::DisableBreakpoint,
10684        window: &mut Window,
10685        cx: &mut Context<Self>,
10686    ) {
10687        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10688            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10689                continue;
10690            };
10691            self.edit_breakpoint_at_anchor(
10692                anchor,
10693                breakpoint,
10694                BreakpointEditAction::InvertState,
10695                cx,
10696            );
10697        }
10698    }
10699
10700    pub fn toggle_breakpoint(
10701        &mut self,
10702        _: &crate::actions::ToggleBreakpoint,
10703        window: &mut Window,
10704        cx: &mut Context<Self>,
10705    ) {
10706        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10707            if let Some(breakpoint) = breakpoint {
10708                self.edit_breakpoint_at_anchor(
10709                    anchor,
10710                    breakpoint,
10711                    BreakpointEditAction::Toggle,
10712                    cx,
10713                );
10714            } else {
10715                self.edit_breakpoint_at_anchor(
10716                    anchor,
10717                    Breakpoint::new_standard(),
10718                    BreakpointEditAction::Toggle,
10719                    cx,
10720                );
10721            }
10722        }
10723    }
10724
10725    pub fn edit_breakpoint_at_anchor(
10726        &mut self,
10727        breakpoint_position: Anchor,
10728        breakpoint: Breakpoint,
10729        edit_action: BreakpointEditAction,
10730        cx: &mut Context<Self>,
10731    ) {
10732        let Some(breakpoint_store) = &self.breakpoint_store else {
10733            return;
10734        };
10735
10736        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10737            if breakpoint_position == Anchor::min() {
10738                self.buffer()
10739                    .read(cx)
10740                    .excerpt_buffer_ids()
10741                    .into_iter()
10742                    .next()
10743            } else {
10744                None
10745            }
10746        }) else {
10747            return;
10748        };
10749
10750        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10751            return;
10752        };
10753
10754        breakpoint_store.update(cx, |breakpoint_store, cx| {
10755            breakpoint_store.toggle_breakpoint(
10756                buffer,
10757                BreakpointWithPosition {
10758                    position: breakpoint_position.text_anchor,
10759                    bp: breakpoint,
10760                },
10761                edit_action,
10762                cx,
10763            );
10764        });
10765
10766        cx.notify();
10767    }
10768
10769    #[cfg(any(test, feature = "test-support"))]
10770    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10771        self.breakpoint_store.clone()
10772    }
10773
10774    pub fn prepare_restore_change(
10775        &self,
10776        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10777        hunk: &MultiBufferDiffHunk,
10778        cx: &mut App,
10779    ) -> Option<()> {
10780        if hunk.is_created_file() {
10781            return None;
10782        }
10783        let buffer = self.buffer.read(cx);
10784        let diff = buffer.diff_for(hunk.buffer_id)?;
10785        let buffer = buffer.buffer(hunk.buffer_id)?;
10786        let buffer = buffer.read(cx);
10787        let original_text = diff
10788            .read(cx)
10789            .base_text()
10790            .as_rope()
10791            .slice(hunk.diff_base_byte_range.clone());
10792        let buffer_snapshot = buffer.snapshot();
10793        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10794        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10795            probe
10796                .0
10797                .start
10798                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10799                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10800        }) {
10801            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10802            Some(())
10803        } else {
10804            None
10805        }
10806    }
10807
10808    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10809        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10810    }
10811
10812    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10813        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10814    }
10815
10816    fn manipulate_lines<M>(
10817        &mut self,
10818        window: &mut Window,
10819        cx: &mut Context<Self>,
10820        mut manipulate: M,
10821    ) where
10822        M: FnMut(&str) -> LineManipulationResult,
10823    {
10824        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10825
10826        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10827        let buffer = self.buffer.read(cx).snapshot(cx);
10828
10829        let mut edits = Vec::new();
10830
10831        let selections = self.selections.all::<Point>(cx);
10832        let mut selections = selections.iter().peekable();
10833        let mut contiguous_row_selections = Vec::new();
10834        let mut new_selections = Vec::new();
10835        let mut added_lines = 0;
10836        let mut removed_lines = 0;
10837
10838        while let Some(selection) = selections.next() {
10839            let (start_row, end_row) = consume_contiguous_rows(
10840                &mut contiguous_row_selections,
10841                selection,
10842                &display_map,
10843                &mut selections,
10844            );
10845
10846            let start_point = Point::new(start_row.0, 0);
10847            let end_point = Point::new(
10848                end_row.previous_row().0,
10849                buffer.line_len(end_row.previous_row()),
10850            );
10851            let text = buffer
10852                .text_for_range(start_point..end_point)
10853                .collect::<String>();
10854
10855            let LineManipulationResult {
10856                new_text,
10857                line_count_before,
10858                line_count_after,
10859            } = manipulate(&text);
10860
10861            edits.push((start_point..end_point, new_text));
10862
10863            // Selections must change based on added and removed line count
10864            let start_row =
10865                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10866            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10867            new_selections.push(Selection {
10868                id: selection.id,
10869                start: start_row,
10870                end: end_row,
10871                goal: SelectionGoal::None,
10872                reversed: selection.reversed,
10873            });
10874
10875            if line_count_after > line_count_before {
10876                added_lines += line_count_after - line_count_before;
10877            } else if line_count_before > line_count_after {
10878                removed_lines += line_count_before - line_count_after;
10879            }
10880        }
10881
10882        self.transact(window, cx, |this, window, cx| {
10883            let buffer = this.buffer.update(cx, |buffer, cx| {
10884                buffer.edit(edits, None, cx);
10885                buffer.snapshot(cx)
10886            });
10887
10888            // Recalculate offsets on newly edited buffer
10889            let new_selections = new_selections
10890                .iter()
10891                .map(|s| {
10892                    let start_point = Point::new(s.start.0, 0);
10893                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10894                    Selection {
10895                        id: s.id,
10896                        start: buffer.point_to_offset(start_point),
10897                        end: buffer.point_to_offset(end_point),
10898                        goal: s.goal,
10899                        reversed: s.reversed,
10900                    }
10901                })
10902                .collect();
10903
10904            this.change_selections(Default::default(), window, cx, |s| {
10905                s.select(new_selections);
10906            });
10907
10908            this.request_autoscroll(Autoscroll::fit(), cx);
10909        });
10910    }
10911
10912    fn manipulate_immutable_lines<Fn>(
10913        &mut self,
10914        window: &mut Window,
10915        cx: &mut Context<Self>,
10916        mut callback: Fn,
10917    ) where
10918        Fn: FnMut(&mut Vec<&str>),
10919    {
10920        self.manipulate_lines(window, cx, |text| {
10921            let mut lines: Vec<&str> = text.split('\n').collect();
10922            let line_count_before = lines.len();
10923
10924            callback(&mut lines);
10925
10926            LineManipulationResult {
10927                new_text: lines.join("\n"),
10928                line_count_before,
10929                line_count_after: lines.len(),
10930            }
10931        });
10932    }
10933
10934    fn manipulate_mutable_lines<Fn>(
10935        &mut self,
10936        window: &mut Window,
10937        cx: &mut Context<Self>,
10938        mut callback: Fn,
10939    ) where
10940        Fn: FnMut(&mut Vec<Cow<'_, str>>),
10941    {
10942        self.manipulate_lines(window, cx, |text| {
10943            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
10944            let line_count_before = lines.len();
10945
10946            callback(&mut lines);
10947
10948            LineManipulationResult {
10949                new_text: lines.join("\n"),
10950                line_count_before,
10951                line_count_after: lines.len(),
10952            }
10953        });
10954    }
10955
10956    pub fn convert_indentation_to_spaces(
10957        &mut self,
10958        _: &ConvertIndentationToSpaces,
10959        window: &mut Window,
10960        cx: &mut Context<Self>,
10961    ) {
10962        let settings = self.buffer.read(cx).language_settings(cx);
10963        let tab_size = settings.tab_size.get() as usize;
10964
10965        self.manipulate_mutable_lines(window, cx, |lines| {
10966            // Allocates a reasonably sized scratch buffer once for the whole loop
10967            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10968            // Avoids recomputing spaces that could be inserted many times
10969            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10970                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10971                .collect();
10972
10973            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10974                let mut chars = line.as_ref().chars();
10975                let mut col = 0;
10976                let mut changed = false;
10977
10978                while let Some(ch) = chars.next() {
10979                    match ch {
10980                        ' ' => {
10981                            reindented_line.push(' ');
10982                            col += 1;
10983                        }
10984                        '\t' => {
10985                            // \t are converted to spaces depending on the current column
10986                            let spaces_len = tab_size - (col % tab_size);
10987                            reindented_line.extend(&space_cache[spaces_len - 1]);
10988                            col += spaces_len;
10989                            changed = true;
10990                        }
10991                        _ => {
10992                            // If we dont append before break, the character is consumed
10993                            reindented_line.push(ch);
10994                            break;
10995                        }
10996                    }
10997                }
10998
10999                if !changed {
11000                    reindented_line.clear();
11001                    continue;
11002                }
11003                // Append the rest of the line and replace old reference with new one
11004                reindented_line.extend(chars);
11005                *line = Cow::Owned(reindented_line.clone());
11006                reindented_line.clear();
11007            }
11008        });
11009    }
11010
11011    pub fn convert_indentation_to_tabs(
11012        &mut self,
11013        _: &ConvertIndentationToTabs,
11014        window: &mut Window,
11015        cx: &mut Context<Self>,
11016    ) {
11017        let settings = self.buffer.read(cx).language_settings(cx);
11018        let tab_size = settings.tab_size.get() as usize;
11019
11020        self.manipulate_mutable_lines(window, cx, |lines| {
11021            // Allocates a reasonably sized buffer once for the whole loop
11022            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11023            // Avoids recomputing spaces that could be inserted many times
11024            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11025                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11026                .collect();
11027
11028            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11029                let mut chars = line.chars();
11030                let mut spaces_count = 0;
11031                let mut first_non_indent_char = None;
11032                let mut changed = false;
11033
11034                while let Some(ch) = chars.next() {
11035                    match ch {
11036                        ' ' => {
11037                            // Keep track of spaces. Append \t when we reach tab_size
11038                            spaces_count += 1;
11039                            changed = true;
11040                            if spaces_count == tab_size {
11041                                reindented_line.push('\t');
11042                                spaces_count = 0;
11043                            }
11044                        }
11045                        '\t' => {
11046                            reindented_line.push('\t');
11047                            spaces_count = 0;
11048                        }
11049                        _ => {
11050                            // Dont append it yet, we might have remaining spaces
11051                            first_non_indent_char = Some(ch);
11052                            break;
11053                        }
11054                    }
11055                }
11056
11057                if !changed {
11058                    reindented_line.clear();
11059                    continue;
11060                }
11061                // Remaining spaces that didn't make a full tab stop
11062                if spaces_count > 0 {
11063                    reindented_line.extend(&space_cache[spaces_count - 1]);
11064                }
11065                // If we consume an extra character that was not indentation, add it back
11066                if let Some(extra_char) = first_non_indent_char {
11067                    reindented_line.push(extra_char);
11068                }
11069                // Append the rest of the line and replace old reference with new one
11070                reindented_line.extend(chars);
11071                *line = Cow::Owned(reindented_line.clone());
11072                reindented_line.clear();
11073            }
11074        });
11075    }
11076
11077    pub fn convert_to_upper_case(
11078        &mut self,
11079        _: &ConvertToUpperCase,
11080        window: &mut Window,
11081        cx: &mut Context<Self>,
11082    ) {
11083        self.manipulate_text(window, cx, |text| text.to_uppercase())
11084    }
11085
11086    pub fn convert_to_lower_case(
11087        &mut self,
11088        _: &ConvertToLowerCase,
11089        window: &mut Window,
11090        cx: &mut Context<Self>,
11091    ) {
11092        self.manipulate_text(window, cx, |text| text.to_lowercase())
11093    }
11094
11095    pub fn convert_to_title_case(
11096        &mut self,
11097        _: &ConvertToTitleCase,
11098        window: &mut Window,
11099        cx: &mut Context<Self>,
11100    ) {
11101        self.manipulate_text(window, cx, |text| {
11102            text.split('\n')
11103                .map(|line| line.to_case(Case::Title))
11104                .join("\n")
11105        })
11106    }
11107
11108    pub fn convert_to_snake_case(
11109        &mut self,
11110        _: &ConvertToSnakeCase,
11111        window: &mut Window,
11112        cx: &mut Context<Self>,
11113    ) {
11114        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11115    }
11116
11117    pub fn convert_to_kebab_case(
11118        &mut self,
11119        _: &ConvertToKebabCase,
11120        window: &mut Window,
11121        cx: &mut Context<Self>,
11122    ) {
11123        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11124    }
11125
11126    pub fn convert_to_upper_camel_case(
11127        &mut self,
11128        _: &ConvertToUpperCamelCase,
11129        window: &mut Window,
11130        cx: &mut Context<Self>,
11131    ) {
11132        self.manipulate_text(window, cx, |text| {
11133            text.split('\n')
11134                .map(|line| line.to_case(Case::UpperCamel))
11135                .join("\n")
11136        })
11137    }
11138
11139    pub fn convert_to_lower_camel_case(
11140        &mut self,
11141        _: &ConvertToLowerCamelCase,
11142        window: &mut Window,
11143        cx: &mut Context<Self>,
11144    ) {
11145        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11146    }
11147
11148    pub fn convert_to_opposite_case(
11149        &mut self,
11150        _: &ConvertToOppositeCase,
11151        window: &mut Window,
11152        cx: &mut Context<Self>,
11153    ) {
11154        self.manipulate_text(window, cx, |text| {
11155            text.chars()
11156                .fold(String::with_capacity(text.len()), |mut t, c| {
11157                    if c.is_uppercase() {
11158                        t.extend(c.to_lowercase());
11159                    } else {
11160                        t.extend(c.to_uppercase());
11161                    }
11162                    t
11163                })
11164        })
11165    }
11166
11167    pub fn convert_to_sentence_case(
11168        &mut self,
11169        _: &ConvertToSentenceCase,
11170        window: &mut Window,
11171        cx: &mut Context<Self>,
11172    ) {
11173        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11174    }
11175
11176    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11177        self.manipulate_text(window, cx, |text| {
11178            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11179            if has_upper_case_characters {
11180                text.to_lowercase()
11181            } else {
11182                text.to_uppercase()
11183            }
11184        })
11185    }
11186
11187    pub fn convert_to_rot13(
11188        &mut self,
11189        _: &ConvertToRot13,
11190        window: &mut Window,
11191        cx: &mut Context<Self>,
11192    ) {
11193        self.manipulate_text(window, cx, |text| {
11194            text.chars()
11195                .map(|c| match c {
11196                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11197                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11198                    _ => c,
11199                })
11200                .collect()
11201        })
11202    }
11203
11204    pub fn convert_to_rot47(
11205        &mut self,
11206        _: &ConvertToRot47,
11207        window: &mut Window,
11208        cx: &mut Context<Self>,
11209    ) {
11210        self.manipulate_text(window, cx, |text| {
11211            text.chars()
11212                .map(|c| {
11213                    let code_point = c as u32;
11214                    if code_point >= 33 && code_point <= 126 {
11215                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11216                    }
11217                    c
11218                })
11219                .collect()
11220        })
11221    }
11222
11223    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11224    where
11225        Fn: FnMut(&str) -> String,
11226    {
11227        let buffer = self.buffer.read(cx).snapshot(cx);
11228
11229        let mut new_selections = Vec::new();
11230        let mut edits = Vec::new();
11231        let mut selection_adjustment = 0i32;
11232
11233        for selection in self.selections.all::<usize>(cx) {
11234            let selection_is_empty = selection.is_empty();
11235
11236            let (start, end) = if selection_is_empty {
11237                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11238                (word_range.start, word_range.end)
11239            } else {
11240                (selection.start, selection.end)
11241            };
11242
11243            let text = buffer.text_for_range(start..end).collect::<String>();
11244            let old_length = text.len() as i32;
11245            let text = callback(&text);
11246
11247            new_selections.push(Selection {
11248                start: (start as i32 - selection_adjustment) as usize,
11249                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11250                goal: SelectionGoal::None,
11251                ..selection
11252            });
11253
11254            selection_adjustment += old_length - text.len() as i32;
11255
11256            edits.push((start..end, text));
11257        }
11258
11259        self.transact(window, cx, |this, window, cx| {
11260            this.buffer.update(cx, |buffer, cx| {
11261                buffer.edit(edits, None, cx);
11262            });
11263
11264            this.change_selections(Default::default(), window, cx, |s| {
11265                s.select(new_selections);
11266            });
11267
11268            this.request_autoscroll(Autoscroll::fit(), cx);
11269        });
11270    }
11271
11272    pub fn move_selection_on_drop(
11273        &mut self,
11274        selection: &Selection<Anchor>,
11275        target: DisplayPoint,
11276        is_cut: bool,
11277        window: &mut Window,
11278        cx: &mut Context<Self>,
11279    ) {
11280        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11281        let buffer = &display_map.buffer_snapshot;
11282        let mut edits = Vec::new();
11283        let insert_point = display_map
11284            .clip_point(target, Bias::Left)
11285            .to_point(&display_map);
11286        let text = buffer
11287            .text_for_range(selection.start..selection.end)
11288            .collect::<String>();
11289        if is_cut {
11290            edits.push(((selection.start..selection.end), String::new()));
11291        }
11292        let insert_anchor = buffer.anchor_before(insert_point);
11293        edits.push(((insert_anchor..insert_anchor), text));
11294        let last_edit_start = insert_anchor.bias_left(buffer);
11295        let last_edit_end = insert_anchor.bias_right(buffer);
11296        self.transact(window, cx, |this, window, cx| {
11297            this.buffer.update(cx, |buffer, cx| {
11298                buffer.edit(edits, None, cx);
11299            });
11300            this.change_selections(Default::default(), window, cx, |s| {
11301                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11302            });
11303        });
11304    }
11305
11306    pub fn clear_selection_drag_state(&mut self) {
11307        self.selection_drag_state = SelectionDragState::None;
11308    }
11309
11310    pub fn duplicate(
11311        &mut self,
11312        upwards: bool,
11313        whole_lines: bool,
11314        window: &mut Window,
11315        cx: &mut Context<Self>,
11316    ) {
11317        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11318
11319        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11320        let buffer = &display_map.buffer_snapshot;
11321        let selections = self.selections.all::<Point>(cx);
11322
11323        let mut edits = Vec::new();
11324        let mut selections_iter = selections.iter().peekable();
11325        while let Some(selection) = selections_iter.next() {
11326            let mut rows = selection.spanned_rows(false, &display_map);
11327            // duplicate line-wise
11328            if whole_lines || selection.start == selection.end {
11329                // Avoid duplicating the same lines twice.
11330                while let Some(next_selection) = selections_iter.peek() {
11331                    let next_rows = next_selection.spanned_rows(false, &display_map);
11332                    if next_rows.start < rows.end {
11333                        rows.end = next_rows.end;
11334                        selections_iter.next().unwrap();
11335                    } else {
11336                        break;
11337                    }
11338                }
11339
11340                // Copy the text from the selected row region and splice it either at the start
11341                // or end of the region.
11342                let start = Point::new(rows.start.0, 0);
11343                let end = Point::new(
11344                    rows.end.previous_row().0,
11345                    buffer.line_len(rows.end.previous_row()),
11346                );
11347                let text = buffer
11348                    .text_for_range(start..end)
11349                    .chain(Some("\n"))
11350                    .collect::<String>();
11351                let insert_location = if upwards {
11352                    Point::new(rows.end.0, 0)
11353                } else {
11354                    start
11355                };
11356                edits.push((insert_location..insert_location, text));
11357            } else {
11358                // duplicate character-wise
11359                let start = selection.start;
11360                let end = selection.end;
11361                let text = buffer.text_for_range(start..end).collect::<String>();
11362                edits.push((selection.end..selection.end, text));
11363            }
11364        }
11365
11366        self.transact(window, cx, |this, _, cx| {
11367            this.buffer.update(cx, |buffer, cx| {
11368                buffer.edit(edits, None, cx);
11369            });
11370
11371            this.request_autoscroll(Autoscroll::fit(), cx);
11372        });
11373    }
11374
11375    pub fn duplicate_line_up(
11376        &mut self,
11377        _: &DuplicateLineUp,
11378        window: &mut Window,
11379        cx: &mut Context<Self>,
11380    ) {
11381        self.duplicate(true, true, window, cx);
11382    }
11383
11384    pub fn duplicate_line_down(
11385        &mut self,
11386        _: &DuplicateLineDown,
11387        window: &mut Window,
11388        cx: &mut Context<Self>,
11389    ) {
11390        self.duplicate(false, true, window, cx);
11391    }
11392
11393    pub fn duplicate_selection(
11394        &mut self,
11395        _: &DuplicateSelection,
11396        window: &mut Window,
11397        cx: &mut Context<Self>,
11398    ) {
11399        self.duplicate(false, false, window, cx);
11400    }
11401
11402    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11403        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11404        if self.mode.is_single_line() {
11405            cx.propagate();
11406            return;
11407        }
11408
11409        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11410        let buffer = self.buffer.read(cx).snapshot(cx);
11411
11412        let mut edits = Vec::new();
11413        let mut unfold_ranges = Vec::new();
11414        let mut refold_creases = Vec::new();
11415
11416        let selections = self.selections.all::<Point>(cx);
11417        let mut selections = selections.iter().peekable();
11418        let mut contiguous_row_selections = Vec::new();
11419        let mut new_selections = Vec::new();
11420
11421        while let Some(selection) = selections.next() {
11422            // Find all the selections that span a contiguous row range
11423            let (start_row, end_row) = consume_contiguous_rows(
11424                &mut contiguous_row_selections,
11425                selection,
11426                &display_map,
11427                &mut selections,
11428            );
11429
11430            // Move the text spanned by the row range to be before the line preceding the row range
11431            if start_row.0 > 0 {
11432                let range_to_move = Point::new(
11433                    start_row.previous_row().0,
11434                    buffer.line_len(start_row.previous_row()),
11435                )
11436                    ..Point::new(
11437                        end_row.previous_row().0,
11438                        buffer.line_len(end_row.previous_row()),
11439                    );
11440                let insertion_point = display_map
11441                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11442                    .0;
11443
11444                // Don't move lines across excerpts
11445                if buffer
11446                    .excerpt_containing(insertion_point..range_to_move.end)
11447                    .is_some()
11448                {
11449                    let text = buffer
11450                        .text_for_range(range_to_move.clone())
11451                        .flat_map(|s| s.chars())
11452                        .skip(1)
11453                        .chain(['\n'])
11454                        .collect::<String>();
11455
11456                    edits.push((
11457                        buffer.anchor_after(range_to_move.start)
11458                            ..buffer.anchor_before(range_to_move.end),
11459                        String::new(),
11460                    ));
11461                    let insertion_anchor = buffer.anchor_after(insertion_point);
11462                    edits.push((insertion_anchor..insertion_anchor, text));
11463
11464                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11465
11466                    // Move selections up
11467                    new_selections.extend(contiguous_row_selections.drain(..).map(
11468                        |mut selection| {
11469                            selection.start.row -= row_delta;
11470                            selection.end.row -= row_delta;
11471                            selection
11472                        },
11473                    ));
11474
11475                    // Move folds up
11476                    unfold_ranges.push(range_to_move.clone());
11477                    for fold in display_map.folds_in_range(
11478                        buffer.anchor_before(range_to_move.start)
11479                            ..buffer.anchor_after(range_to_move.end),
11480                    ) {
11481                        let mut start = fold.range.start.to_point(&buffer);
11482                        let mut end = fold.range.end.to_point(&buffer);
11483                        start.row -= row_delta;
11484                        end.row -= row_delta;
11485                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11486                    }
11487                }
11488            }
11489
11490            // If we didn't move line(s), preserve the existing selections
11491            new_selections.append(&mut contiguous_row_selections);
11492        }
11493
11494        self.transact(window, cx, |this, window, cx| {
11495            this.unfold_ranges(&unfold_ranges, true, true, cx);
11496            this.buffer.update(cx, |buffer, cx| {
11497                for (range, text) in edits {
11498                    buffer.edit([(range, text)], None, cx);
11499                }
11500            });
11501            this.fold_creases(refold_creases, true, window, cx);
11502            this.change_selections(Default::default(), window, cx, |s| {
11503                s.select(new_selections);
11504            })
11505        });
11506    }
11507
11508    pub fn move_line_down(
11509        &mut self,
11510        _: &MoveLineDown,
11511        window: &mut Window,
11512        cx: &mut Context<Self>,
11513    ) {
11514        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11515        if self.mode.is_single_line() {
11516            cx.propagate();
11517            return;
11518        }
11519
11520        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11521        let buffer = self.buffer.read(cx).snapshot(cx);
11522
11523        let mut edits = Vec::new();
11524        let mut unfold_ranges = Vec::new();
11525        let mut refold_creases = Vec::new();
11526
11527        let selections = self.selections.all::<Point>(cx);
11528        let mut selections = selections.iter().peekable();
11529        let mut contiguous_row_selections = Vec::new();
11530        let mut new_selections = Vec::new();
11531
11532        while let Some(selection) = selections.next() {
11533            // Find all the selections that span a contiguous row range
11534            let (start_row, end_row) = consume_contiguous_rows(
11535                &mut contiguous_row_selections,
11536                selection,
11537                &display_map,
11538                &mut selections,
11539            );
11540
11541            // Move the text spanned by the row range to be after the last line of the row range
11542            if end_row.0 <= buffer.max_point().row {
11543                let range_to_move =
11544                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11545                let insertion_point = display_map
11546                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11547                    .0;
11548
11549                // Don't move lines across excerpt boundaries
11550                if buffer
11551                    .excerpt_containing(range_to_move.start..insertion_point)
11552                    .is_some()
11553                {
11554                    let mut text = String::from("\n");
11555                    text.extend(buffer.text_for_range(range_to_move.clone()));
11556                    text.pop(); // Drop trailing newline
11557                    edits.push((
11558                        buffer.anchor_after(range_to_move.start)
11559                            ..buffer.anchor_before(range_to_move.end),
11560                        String::new(),
11561                    ));
11562                    let insertion_anchor = buffer.anchor_after(insertion_point);
11563                    edits.push((insertion_anchor..insertion_anchor, text));
11564
11565                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11566
11567                    // Move selections down
11568                    new_selections.extend(contiguous_row_selections.drain(..).map(
11569                        |mut selection| {
11570                            selection.start.row += row_delta;
11571                            selection.end.row += row_delta;
11572                            selection
11573                        },
11574                    ));
11575
11576                    // Move folds down
11577                    unfold_ranges.push(range_to_move.clone());
11578                    for fold in display_map.folds_in_range(
11579                        buffer.anchor_before(range_to_move.start)
11580                            ..buffer.anchor_after(range_to_move.end),
11581                    ) {
11582                        let mut start = fold.range.start.to_point(&buffer);
11583                        let mut end = fold.range.end.to_point(&buffer);
11584                        start.row += row_delta;
11585                        end.row += row_delta;
11586                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11587                    }
11588                }
11589            }
11590
11591            // If we didn't move line(s), preserve the existing selections
11592            new_selections.append(&mut contiguous_row_selections);
11593        }
11594
11595        self.transact(window, cx, |this, window, cx| {
11596            this.unfold_ranges(&unfold_ranges, true, true, cx);
11597            this.buffer.update(cx, |buffer, cx| {
11598                for (range, text) in edits {
11599                    buffer.edit([(range, text)], None, cx);
11600                }
11601            });
11602            this.fold_creases(refold_creases, true, window, cx);
11603            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11604        });
11605    }
11606
11607    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11608        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11609        let text_layout_details = &self.text_layout_details(window);
11610        self.transact(window, cx, |this, window, cx| {
11611            let edits = this.change_selections(Default::default(), window, cx, |s| {
11612                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11613                s.move_with(|display_map, selection| {
11614                    if !selection.is_empty() {
11615                        return;
11616                    }
11617
11618                    let mut head = selection.head();
11619                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11620                    if head.column() == display_map.line_len(head.row()) {
11621                        transpose_offset = display_map
11622                            .buffer_snapshot
11623                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11624                    }
11625
11626                    if transpose_offset == 0 {
11627                        return;
11628                    }
11629
11630                    *head.column_mut() += 1;
11631                    head = display_map.clip_point(head, Bias::Right);
11632                    let goal = SelectionGoal::HorizontalPosition(
11633                        display_map
11634                            .x_for_display_point(head, text_layout_details)
11635                            .into(),
11636                    );
11637                    selection.collapse_to(head, goal);
11638
11639                    let transpose_start = display_map
11640                        .buffer_snapshot
11641                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11642                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11643                        let transpose_end = display_map
11644                            .buffer_snapshot
11645                            .clip_offset(transpose_offset + 1, Bias::Right);
11646                        if let Some(ch) =
11647                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11648                        {
11649                            edits.push((transpose_start..transpose_offset, String::new()));
11650                            edits.push((transpose_end..transpose_end, ch.to_string()));
11651                        }
11652                    }
11653                });
11654                edits
11655            });
11656            this.buffer
11657                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11658            let selections = this.selections.all::<usize>(cx);
11659            this.change_selections(Default::default(), window, cx, |s| {
11660                s.select(selections);
11661            });
11662        });
11663    }
11664
11665    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11666        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11667        if self.mode.is_single_line() {
11668            cx.propagate();
11669            return;
11670        }
11671
11672        self.rewrap_impl(RewrapOptions::default(), cx)
11673    }
11674
11675    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11676        let buffer = self.buffer.read(cx).snapshot(cx);
11677        let selections = self.selections.all::<Point>(cx);
11678
11679        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11680        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11681            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11682                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11683                .peekable();
11684
11685            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11686                row
11687            } else {
11688                return Vec::new();
11689            };
11690
11691            let language_settings = buffer.language_settings_at(selection.head(), cx);
11692            let language_scope = buffer.language_scope_at(selection.head());
11693
11694            let indent_and_prefix_for_row =
11695                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11696                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11697                    let (comment_prefix, rewrap_prefix) =
11698                        if let Some(language_scope) = &language_scope {
11699                            let indent_end = Point::new(row, indent.len);
11700                            let comment_prefix = language_scope
11701                                .line_comment_prefixes()
11702                                .iter()
11703                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11704                                .map(|prefix| prefix.to_string());
11705                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11706                            let line_text_after_indent = buffer
11707                                .text_for_range(indent_end..line_end)
11708                                .collect::<String>();
11709                            let rewrap_prefix = language_scope
11710                                .rewrap_prefixes()
11711                                .iter()
11712                                .find_map(|prefix_regex| {
11713                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11714                                        if mat.start() == 0 {
11715                                            Some(mat.as_str().to_string())
11716                                        } else {
11717                                            None
11718                                        }
11719                                    })
11720                                })
11721                                .flatten();
11722                            (comment_prefix, rewrap_prefix)
11723                        } else {
11724                            (None, None)
11725                        };
11726                    (indent, comment_prefix, rewrap_prefix)
11727                };
11728
11729            let mut ranges = Vec::new();
11730            let from_empty_selection = selection.is_empty();
11731
11732            let mut current_range_start = first_row;
11733            let mut prev_row = first_row;
11734            let (
11735                mut current_range_indent,
11736                mut current_range_comment_prefix,
11737                mut current_range_rewrap_prefix,
11738            ) = indent_and_prefix_for_row(first_row);
11739
11740            for row in non_blank_rows_iter.skip(1) {
11741                let has_paragraph_break = row > prev_row + 1;
11742
11743                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11744                    indent_and_prefix_for_row(row);
11745
11746                let has_indent_change = row_indent != current_range_indent;
11747                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11748
11749                let has_boundary_change = has_comment_change
11750                    || row_rewrap_prefix.is_some()
11751                    || (has_indent_change && current_range_comment_prefix.is_some());
11752
11753                if has_paragraph_break || has_boundary_change {
11754                    ranges.push((
11755                        language_settings.clone(),
11756                        Point::new(current_range_start, 0)
11757                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11758                        current_range_indent,
11759                        current_range_comment_prefix.clone(),
11760                        current_range_rewrap_prefix.clone(),
11761                        from_empty_selection,
11762                    ));
11763                    current_range_start = row;
11764                    current_range_indent = row_indent;
11765                    current_range_comment_prefix = row_comment_prefix;
11766                    current_range_rewrap_prefix = row_rewrap_prefix;
11767                }
11768                prev_row = row;
11769            }
11770
11771            ranges.push((
11772                language_settings.clone(),
11773                Point::new(current_range_start, 0)
11774                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11775                current_range_indent,
11776                current_range_comment_prefix,
11777                current_range_rewrap_prefix,
11778                from_empty_selection,
11779            ));
11780
11781            ranges
11782        });
11783
11784        let mut edits = Vec::new();
11785        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11786
11787        for (
11788            language_settings,
11789            wrap_range,
11790            indent_size,
11791            comment_prefix,
11792            rewrap_prefix,
11793            from_empty_selection,
11794        ) in wrap_ranges
11795        {
11796            let mut start_row = wrap_range.start.row;
11797            let mut end_row = wrap_range.end.row;
11798
11799            // Skip selections that overlap with a range that has already been rewrapped.
11800            let selection_range = start_row..end_row;
11801            if rewrapped_row_ranges
11802                .iter()
11803                .any(|range| range.overlaps(&selection_range))
11804            {
11805                continue;
11806            }
11807
11808            let tab_size = language_settings.tab_size;
11809
11810            let indent_prefix = indent_size.chars().collect::<String>();
11811            let mut line_prefix = indent_prefix.clone();
11812            let mut inside_comment = false;
11813            if let Some(prefix) = &comment_prefix {
11814                line_prefix.push_str(prefix);
11815                inside_comment = true;
11816            }
11817            if let Some(prefix) = &rewrap_prefix {
11818                line_prefix.push_str(prefix);
11819            }
11820
11821            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11822                RewrapBehavior::InComments => inside_comment,
11823                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11824                RewrapBehavior::Anywhere => true,
11825            };
11826
11827            let should_rewrap = options.override_language_settings
11828                || allow_rewrap_based_on_language
11829                || self.hard_wrap.is_some();
11830            if !should_rewrap {
11831                continue;
11832            }
11833
11834            if from_empty_selection {
11835                'expand_upwards: while start_row > 0 {
11836                    let prev_row = start_row - 1;
11837                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11838                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11839                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11840                    {
11841                        start_row = prev_row;
11842                    } else {
11843                        break 'expand_upwards;
11844                    }
11845                }
11846
11847                'expand_downwards: while end_row < buffer.max_point().row {
11848                    let next_row = end_row + 1;
11849                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11850                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11851                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11852                    {
11853                        end_row = next_row;
11854                    } else {
11855                        break 'expand_downwards;
11856                    }
11857                }
11858            }
11859
11860            let start = Point::new(start_row, 0);
11861            let start_offset = start.to_offset(&buffer);
11862            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11863            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11864            let Some(lines_without_prefixes) = selection_text
11865                .lines()
11866                .enumerate()
11867                .map(|(ix, line)| {
11868                    let line_trimmed = line.trim_start();
11869                    if rewrap_prefix.is_some() && ix > 0 {
11870                        Ok(line_trimmed)
11871                    } else {
11872                        line_trimmed
11873                            .strip_prefix(&line_prefix.trim_start())
11874                            .with_context(|| {
11875                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11876                            })
11877                    }
11878                })
11879                .collect::<Result<Vec<_>, _>>()
11880                .log_err()
11881            else {
11882                continue;
11883            };
11884
11885            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11886                buffer
11887                    .language_settings_at(Point::new(start_row, 0), cx)
11888                    .preferred_line_length as usize
11889            });
11890
11891            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11892                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11893            } else {
11894                line_prefix.clone()
11895            };
11896
11897            let wrapped_text = wrap_with_prefix(
11898                line_prefix,
11899                subsequent_lines_prefix,
11900                lines_without_prefixes.join("\n"),
11901                wrap_column,
11902                tab_size,
11903                options.preserve_existing_whitespace,
11904            );
11905
11906            // TODO: should always use char-based diff while still supporting cursor behavior that
11907            // matches vim.
11908            let mut diff_options = DiffOptions::default();
11909            if options.override_language_settings {
11910                diff_options.max_word_diff_len = 0;
11911                diff_options.max_word_diff_line_count = 0;
11912            } else {
11913                diff_options.max_word_diff_len = usize::MAX;
11914                diff_options.max_word_diff_line_count = usize::MAX;
11915            }
11916
11917            for (old_range, new_text) in
11918                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11919            {
11920                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11921                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11922                edits.push((edit_start..edit_end, new_text));
11923            }
11924
11925            rewrapped_row_ranges.push(start_row..=end_row);
11926        }
11927
11928        self.buffer
11929            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11930    }
11931
11932    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11933        let mut text = String::new();
11934        let buffer = self.buffer.read(cx).snapshot(cx);
11935        let mut selections = self.selections.all::<Point>(cx);
11936        let mut clipboard_selections = Vec::with_capacity(selections.len());
11937        {
11938            let max_point = buffer.max_point();
11939            let mut is_first = true;
11940            for selection in &mut selections {
11941                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11942                if is_entire_line {
11943                    selection.start = Point::new(selection.start.row, 0);
11944                    if !selection.is_empty() && selection.end.column == 0 {
11945                        selection.end = cmp::min(max_point, selection.end);
11946                    } else {
11947                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11948                    }
11949                    selection.goal = SelectionGoal::None;
11950                }
11951                if is_first {
11952                    is_first = false;
11953                } else {
11954                    text += "\n";
11955                }
11956                let mut len = 0;
11957                for chunk in buffer.text_for_range(selection.start..selection.end) {
11958                    text.push_str(chunk);
11959                    len += chunk.len();
11960                }
11961                clipboard_selections.push(ClipboardSelection {
11962                    len,
11963                    is_entire_line,
11964                    first_line_indent: buffer
11965                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11966                        .len,
11967                });
11968            }
11969        }
11970
11971        self.transact(window, cx, |this, window, cx| {
11972            this.change_selections(Default::default(), window, cx, |s| {
11973                s.select(selections);
11974            });
11975            this.insert("", window, cx);
11976        });
11977        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11978    }
11979
11980    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11981        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11982        let item = self.cut_common(window, cx);
11983        cx.write_to_clipboard(item);
11984    }
11985
11986    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11987        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11988        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11989            s.move_with(|snapshot, sel| {
11990                if sel.is_empty() {
11991                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11992                }
11993            });
11994        });
11995        let item = self.cut_common(window, cx);
11996        cx.set_global(KillRing(item))
11997    }
11998
11999    pub fn kill_ring_yank(
12000        &mut self,
12001        _: &KillRingYank,
12002        window: &mut Window,
12003        cx: &mut Context<Self>,
12004    ) {
12005        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12006        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12007            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12008                (kill_ring.text().to_string(), kill_ring.metadata_json())
12009            } else {
12010                return;
12011            }
12012        } else {
12013            return;
12014        };
12015        self.do_paste(&text, metadata, false, window, cx);
12016    }
12017
12018    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12019        self.do_copy(true, cx);
12020    }
12021
12022    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12023        self.do_copy(false, cx);
12024    }
12025
12026    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12027        let selections = self.selections.all::<Point>(cx);
12028        let buffer = self.buffer.read(cx).read(cx);
12029        let mut text = String::new();
12030
12031        let mut clipboard_selections = Vec::with_capacity(selections.len());
12032        {
12033            let max_point = buffer.max_point();
12034            let mut is_first = true;
12035            for selection in &selections {
12036                let mut start = selection.start;
12037                let mut end = selection.end;
12038                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12039                if is_entire_line {
12040                    start = Point::new(start.row, 0);
12041                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12042                }
12043
12044                let mut trimmed_selections = Vec::new();
12045                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12046                    let row = MultiBufferRow(start.row);
12047                    let first_indent = buffer.indent_size_for_line(row);
12048                    if first_indent.len == 0 || start.column > first_indent.len {
12049                        trimmed_selections.push(start..end);
12050                    } else {
12051                        trimmed_selections.push(
12052                            Point::new(row.0, first_indent.len)
12053                                ..Point::new(row.0, buffer.line_len(row)),
12054                        );
12055                        for row in start.row + 1..=end.row {
12056                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12057                            if row == end.row {
12058                                line_len = end.column;
12059                            }
12060                            if line_len == 0 {
12061                                trimmed_selections
12062                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12063                                continue;
12064                            }
12065                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12066                            if row_indent_size.len >= first_indent.len {
12067                                trimmed_selections.push(
12068                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12069                                );
12070                            } else {
12071                                trimmed_selections.clear();
12072                                trimmed_selections.push(start..end);
12073                                break;
12074                            }
12075                        }
12076                    }
12077                } else {
12078                    trimmed_selections.push(start..end);
12079                }
12080
12081                for trimmed_range in trimmed_selections {
12082                    if is_first {
12083                        is_first = false;
12084                    } else {
12085                        text += "\n";
12086                    }
12087                    let mut len = 0;
12088                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12089                        text.push_str(chunk);
12090                        len += chunk.len();
12091                    }
12092                    clipboard_selections.push(ClipboardSelection {
12093                        len,
12094                        is_entire_line,
12095                        first_line_indent: buffer
12096                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12097                            .len,
12098                    });
12099                }
12100            }
12101        }
12102
12103        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12104            text,
12105            clipboard_selections,
12106        ));
12107    }
12108
12109    pub fn do_paste(
12110        &mut self,
12111        text: &String,
12112        clipboard_selections: Option<Vec<ClipboardSelection>>,
12113        handle_entire_lines: bool,
12114        window: &mut Window,
12115        cx: &mut Context<Self>,
12116    ) {
12117        if self.read_only(cx) {
12118            return;
12119        }
12120
12121        let clipboard_text = Cow::Borrowed(text);
12122
12123        self.transact(window, cx, |this, window, cx| {
12124            if let Some(mut clipboard_selections) = clipboard_selections {
12125                let old_selections = this.selections.all::<usize>(cx);
12126                let all_selections_were_entire_line =
12127                    clipboard_selections.iter().all(|s| s.is_entire_line);
12128                let first_selection_indent_column =
12129                    clipboard_selections.first().map(|s| s.first_line_indent);
12130                if clipboard_selections.len() != old_selections.len() {
12131                    clipboard_selections.drain(..);
12132                }
12133                let cursor_offset = this.selections.last::<usize>(cx).head();
12134                let mut auto_indent_on_paste = true;
12135
12136                this.buffer.update(cx, |buffer, cx| {
12137                    let snapshot = buffer.read(cx);
12138                    auto_indent_on_paste = snapshot
12139                        .language_settings_at(cursor_offset, cx)
12140                        .auto_indent_on_paste;
12141
12142                    let mut start_offset = 0;
12143                    let mut edits = Vec::new();
12144                    let mut original_indent_columns = Vec::new();
12145                    for (ix, selection) in old_selections.iter().enumerate() {
12146                        let to_insert;
12147                        let entire_line;
12148                        let original_indent_column;
12149                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12150                            let end_offset = start_offset + clipboard_selection.len;
12151                            to_insert = &clipboard_text[start_offset..end_offset];
12152                            entire_line = clipboard_selection.is_entire_line;
12153                            start_offset = end_offset + 1;
12154                            original_indent_column = Some(clipboard_selection.first_line_indent);
12155                        } else {
12156                            to_insert = clipboard_text.as_str();
12157                            entire_line = all_selections_were_entire_line;
12158                            original_indent_column = first_selection_indent_column
12159                        }
12160
12161                        // If the corresponding selection was empty when this slice of the
12162                        // clipboard text was written, then the entire line containing the
12163                        // selection was copied. If this selection is also currently empty,
12164                        // then paste the line before the current line of the buffer.
12165                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12166                            let column = selection.start.to_point(&snapshot).column as usize;
12167                            let line_start = selection.start - column;
12168                            line_start..line_start
12169                        } else {
12170                            selection.range()
12171                        };
12172
12173                        edits.push((range, to_insert));
12174                        original_indent_columns.push(original_indent_column);
12175                    }
12176                    drop(snapshot);
12177
12178                    buffer.edit(
12179                        edits,
12180                        if auto_indent_on_paste {
12181                            Some(AutoindentMode::Block {
12182                                original_indent_columns,
12183                            })
12184                        } else {
12185                            None
12186                        },
12187                        cx,
12188                    );
12189                });
12190
12191                let selections = this.selections.all::<usize>(cx);
12192                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12193            } else {
12194                this.insert(&clipboard_text, window, cx);
12195            }
12196        });
12197    }
12198
12199    pub fn diff_clipboard_with_selection(
12200        &mut self,
12201        _: &DiffClipboardWithSelection,
12202        window: &mut Window,
12203        cx: &mut Context<Self>,
12204    ) {
12205        let selections = self.selections.all::<usize>(cx);
12206
12207        if selections.is_empty() {
12208            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12209            return;
12210        };
12211
12212        let clipboard_text = match cx.read_from_clipboard() {
12213            Some(item) => match item.entries().first() {
12214                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12215                _ => None,
12216            },
12217            None => None,
12218        };
12219
12220        let Some(clipboard_text) = clipboard_text else {
12221            log::warn!("Clipboard doesn't contain text.");
12222            return;
12223        };
12224
12225        window.dispatch_action(
12226            Box::new(DiffClipboardWithSelectionData {
12227                clipboard_text,
12228                editor: cx.entity(),
12229            }),
12230            cx,
12231        );
12232    }
12233
12234    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12235        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12236        if let Some(item) = cx.read_from_clipboard() {
12237            let entries = item.entries();
12238
12239            match entries.first() {
12240                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12241                // of all the pasted entries.
12242                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12243                    .do_paste(
12244                        clipboard_string.text(),
12245                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12246                        true,
12247                        window,
12248                        cx,
12249                    ),
12250                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12251            }
12252        }
12253    }
12254
12255    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12256        if self.read_only(cx) {
12257            return;
12258        }
12259
12260        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12261
12262        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12263            if let Some((selections, _)) =
12264                self.selection_history.transaction(transaction_id).cloned()
12265            {
12266                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12267                    s.select_anchors(selections.to_vec());
12268                });
12269            } else {
12270                log::error!(
12271                    "No entry in selection_history found for undo. \
12272                     This may correspond to a bug where undo does not update the selection. \
12273                     If this is occurring, please add details to \
12274                     https://github.com/zed-industries/zed/issues/22692"
12275                );
12276            }
12277            self.request_autoscroll(Autoscroll::fit(), cx);
12278            self.unmark_text(window, cx);
12279            self.refresh_edit_prediction(true, false, window, cx);
12280            cx.emit(EditorEvent::Edited { transaction_id });
12281            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12282        }
12283    }
12284
12285    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12286        if self.read_only(cx) {
12287            return;
12288        }
12289
12290        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12291
12292        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12293            if let Some((_, Some(selections))) =
12294                self.selection_history.transaction(transaction_id).cloned()
12295            {
12296                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12297                    s.select_anchors(selections.to_vec());
12298                });
12299            } else {
12300                log::error!(
12301                    "No entry in selection_history found for redo. \
12302                     This may correspond to a bug where undo does not update the selection. \
12303                     If this is occurring, please add details to \
12304                     https://github.com/zed-industries/zed/issues/22692"
12305                );
12306            }
12307            self.request_autoscroll(Autoscroll::fit(), cx);
12308            self.unmark_text(window, cx);
12309            self.refresh_edit_prediction(true, false, window, cx);
12310            cx.emit(EditorEvent::Edited { transaction_id });
12311        }
12312    }
12313
12314    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12315        self.buffer
12316            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12317    }
12318
12319    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12320        self.buffer
12321            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12322    }
12323
12324    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12325        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12326        self.change_selections(Default::default(), window, cx, |s| {
12327            s.move_with(|map, selection| {
12328                let cursor = if selection.is_empty() {
12329                    movement::left(map, selection.start)
12330                } else {
12331                    selection.start
12332                };
12333                selection.collapse_to(cursor, SelectionGoal::None);
12334            });
12335        })
12336    }
12337
12338    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12339        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12340        self.change_selections(Default::default(), window, cx, |s| {
12341            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12342        })
12343    }
12344
12345    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12346        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12347        self.change_selections(Default::default(), window, cx, |s| {
12348            s.move_with(|map, selection| {
12349                let cursor = if selection.is_empty() {
12350                    movement::right(map, selection.end)
12351                } else {
12352                    selection.end
12353                };
12354                selection.collapse_to(cursor, SelectionGoal::None)
12355            });
12356        })
12357    }
12358
12359    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12360        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12361        self.change_selections(Default::default(), window, cx, |s| {
12362            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12363        })
12364    }
12365
12366    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12367        if self.take_rename(true, window, cx).is_some() {
12368            return;
12369        }
12370
12371        if self.mode.is_single_line() {
12372            cx.propagate();
12373            return;
12374        }
12375
12376        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12377
12378        let text_layout_details = &self.text_layout_details(window);
12379        let selection_count = self.selections.count();
12380        let first_selection = self.selections.first_anchor();
12381
12382        self.change_selections(Default::default(), window, cx, |s| {
12383            s.move_with(|map, selection| {
12384                if !selection.is_empty() {
12385                    selection.goal = SelectionGoal::None;
12386                }
12387                let (cursor, goal) = movement::up(
12388                    map,
12389                    selection.start,
12390                    selection.goal,
12391                    false,
12392                    text_layout_details,
12393                );
12394                selection.collapse_to(cursor, goal);
12395            });
12396        });
12397
12398        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12399        {
12400            cx.propagate();
12401        }
12402    }
12403
12404    pub fn move_up_by_lines(
12405        &mut self,
12406        action: &MoveUpByLines,
12407        window: &mut Window,
12408        cx: &mut Context<Self>,
12409    ) {
12410        if self.take_rename(true, window, cx).is_some() {
12411            return;
12412        }
12413
12414        if self.mode.is_single_line() {
12415            cx.propagate();
12416            return;
12417        }
12418
12419        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12420
12421        let text_layout_details = &self.text_layout_details(window);
12422
12423        self.change_selections(Default::default(), window, cx, |s| {
12424            s.move_with(|map, selection| {
12425                if !selection.is_empty() {
12426                    selection.goal = SelectionGoal::None;
12427                }
12428                let (cursor, goal) = movement::up_by_rows(
12429                    map,
12430                    selection.start,
12431                    action.lines,
12432                    selection.goal,
12433                    false,
12434                    text_layout_details,
12435                );
12436                selection.collapse_to(cursor, goal);
12437            });
12438        })
12439    }
12440
12441    pub fn move_down_by_lines(
12442        &mut self,
12443        action: &MoveDownByLines,
12444        window: &mut Window,
12445        cx: &mut Context<Self>,
12446    ) {
12447        if self.take_rename(true, window, cx).is_some() {
12448            return;
12449        }
12450
12451        if self.mode.is_single_line() {
12452            cx.propagate();
12453            return;
12454        }
12455
12456        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12457
12458        let text_layout_details = &self.text_layout_details(window);
12459
12460        self.change_selections(Default::default(), window, cx, |s| {
12461            s.move_with(|map, selection| {
12462                if !selection.is_empty() {
12463                    selection.goal = SelectionGoal::None;
12464                }
12465                let (cursor, goal) = movement::down_by_rows(
12466                    map,
12467                    selection.start,
12468                    action.lines,
12469                    selection.goal,
12470                    false,
12471                    text_layout_details,
12472                );
12473                selection.collapse_to(cursor, goal);
12474            });
12475        })
12476    }
12477
12478    pub fn select_down_by_lines(
12479        &mut self,
12480        action: &SelectDownByLines,
12481        window: &mut Window,
12482        cx: &mut Context<Self>,
12483    ) {
12484        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12485        let text_layout_details = &self.text_layout_details(window);
12486        self.change_selections(Default::default(), window, cx, |s| {
12487            s.move_heads_with(|map, head, goal| {
12488                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12489            })
12490        })
12491    }
12492
12493    pub fn select_up_by_lines(
12494        &mut self,
12495        action: &SelectUpByLines,
12496        window: &mut Window,
12497        cx: &mut Context<Self>,
12498    ) {
12499        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12500        let text_layout_details = &self.text_layout_details(window);
12501        self.change_selections(Default::default(), window, cx, |s| {
12502            s.move_heads_with(|map, head, goal| {
12503                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12504            })
12505        })
12506    }
12507
12508    pub fn select_page_up(
12509        &mut self,
12510        _: &SelectPageUp,
12511        window: &mut Window,
12512        cx: &mut Context<Self>,
12513    ) {
12514        let Some(row_count) = self.visible_row_count() else {
12515            return;
12516        };
12517
12518        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12519
12520        let text_layout_details = &self.text_layout_details(window);
12521
12522        self.change_selections(Default::default(), window, cx, |s| {
12523            s.move_heads_with(|map, head, goal| {
12524                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12525            })
12526        })
12527    }
12528
12529    pub fn move_page_up(
12530        &mut self,
12531        action: &MovePageUp,
12532        window: &mut Window,
12533        cx: &mut Context<Self>,
12534    ) {
12535        if self.take_rename(true, window, cx).is_some() {
12536            return;
12537        }
12538
12539        if self
12540            .context_menu
12541            .borrow_mut()
12542            .as_mut()
12543            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12544            .unwrap_or(false)
12545        {
12546            return;
12547        }
12548
12549        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12550            cx.propagate();
12551            return;
12552        }
12553
12554        let Some(row_count) = self.visible_row_count() else {
12555            return;
12556        };
12557
12558        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12559
12560        let effects = if action.center_cursor {
12561            SelectionEffects::scroll(Autoscroll::center())
12562        } else {
12563            SelectionEffects::default()
12564        };
12565
12566        let text_layout_details = &self.text_layout_details(window);
12567
12568        self.change_selections(effects, window, cx, |s| {
12569            s.move_with(|map, selection| {
12570                if !selection.is_empty() {
12571                    selection.goal = SelectionGoal::None;
12572                }
12573                let (cursor, goal) = movement::up_by_rows(
12574                    map,
12575                    selection.end,
12576                    row_count,
12577                    selection.goal,
12578                    false,
12579                    text_layout_details,
12580                );
12581                selection.collapse_to(cursor, goal);
12582            });
12583        });
12584    }
12585
12586    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12587        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12588        let text_layout_details = &self.text_layout_details(window);
12589        self.change_selections(Default::default(), window, cx, |s| {
12590            s.move_heads_with(|map, head, goal| {
12591                movement::up(map, head, goal, false, text_layout_details)
12592            })
12593        })
12594    }
12595
12596    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12597        self.take_rename(true, window, cx);
12598
12599        if self.mode.is_single_line() {
12600            cx.propagate();
12601            return;
12602        }
12603
12604        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12605
12606        let text_layout_details = &self.text_layout_details(window);
12607        let selection_count = self.selections.count();
12608        let first_selection = self.selections.first_anchor();
12609
12610        self.change_selections(Default::default(), window, cx, |s| {
12611            s.move_with(|map, selection| {
12612                if !selection.is_empty() {
12613                    selection.goal = SelectionGoal::None;
12614                }
12615                let (cursor, goal) = movement::down(
12616                    map,
12617                    selection.end,
12618                    selection.goal,
12619                    false,
12620                    text_layout_details,
12621                );
12622                selection.collapse_to(cursor, goal);
12623            });
12624        });
12625
12626        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12627        {
12628            cx.propagate();
12629        }
12630    }
12631
12632    pub fn select_page_down(
12633        &mut self,
12634        _: &SelectPageDown,
12635        window: &mut Window,
12636        cx: &mut Context<Self>,
12637    ) {
12638        let Some(row_count) = self.visible_row_count() else {
12639            return;
12640        };
12641
12642        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12643
12644        let text_layout_details = &self.text_layout_details(window);
12645
12646        self.change_selections(Default::default(), window, cx, |s| {
12647            s.move_heads_with(|map, head, goal| {
12648                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12649            })
12650        })
12651    }
12652
12653    pub fn move_page_down(
12654        &mut self,
12655        action: &MovePageDown,
12656        window: &mut Window,
12657        cx: &mut Context<Self>,
12658    ) {
12659        if self.take_rename(true, window, cx).is_some() {
12660            return;
12661        }
12662
12663        if self
12664            .context_menu
12665            .borrow_mut()
12666            .as_mut()
12667            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12668            .unwrap_or(false)
12669        {
12670            return;
12671        }
12672
12673        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12674            cx.propagate();
12675            return;
12676        }
12677
12678        let Some(row_count) = self.visible_row_count() else {
12679            return;
12680        };
12681
12682        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12683
12684        let effects = if action.center_cursor {
12685            SelectionEffects::scroll(Autoscroll::center())
12686        } else {
12687            SelectionEffects::default()
12688        };
12689
12690        let text_layout_details = &self.text_layout_details(window);
12691        self.change_selections(effects, window, cx, |s| {
12692            s.move_with(|map, selection| {
12693                if !selection.is_empty() {
12694                    selection.goal = SelectionGoal::None;
12695                }
12696                let (cursor, goal) = movement::down_by_rows(
12697                    map,
12698                    selection.end,
12699                    row_count,
12700                    selection.goal,
12701                    false,
12702                    text_layout_details,
12703                );
12704                selection.collapse_to(cursor, goal);
12705            });
12706        });
12707    }
12708
12709    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12710        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12711        let text_layout_details = &self.text_layout_details(window);
12712        self.change_selections(Default::default(), window, cx, |s| {
12713            s.move_heads_with(|map, head, goal| {
12714                movement::down(map, head, goal, false, text_layout_details)
12715            })
12716        });
12717    }
12718
12719    pub fn context_menu_first(
12720        &mut self,
12721        _: &ContextMenuFirst,
12722        window: &mut Window,
12723        cx: &mut Context<Self>,
12724    ) {
12725        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12726            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12727        }
12728    }
12729
12730    pub fn context_menu_prev(
12731        &mut self,
12732        _: &ContextMenuPrevious,
12733        window: &mut Window,
12734        cx: &mut Context<Self>,
12735    ) {
12736        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12737            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12738        }
12739    }
12740
12741    pub fn context_menu_next(
12742        &mut self,
12743        _: &ContextMenuNext,
12744        window: &mut Window,
12745        cx: &mut Context<Self>,
12746    ) {
12747        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12748            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12749        }
12750    }
12751
12752    pub fn context_menu_last(
12753        &mut self,
12754        _: &ContextMenuLast,
12755        window: &mut Window,
12756        cx: &mut Context<Self>,
12757    ) {
12758        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12759            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12760        }
12761    }
12762
12763    pub fn signature_help_prev(
12764        &mut self,
12765        _: &SignatureHelpPrevious,
12766        _: &mut Window,
12767        cx: &mut Context<Self>,
12768    ) {
12769        if let Some(popover) = self.signature_help_state.popover_mut() {
12770            if popover.current_signature == 0 {
12771                popover.current_signature = popover.signatures.len() - 1;
12772            } else {
12773                popover.current_signature -= 1;
12774            }
12775            cx.notify();
12776        }
12777    }
12778
12779    pub fn signature_help_next(
12780        &mut self,
12781        _: &SignatureHelpNext,
12782        _: &mut Window,
12783        cx: &mut Context<Self>,
12784    ) {
12785        if let Some(popover) = self.signature_help_state.popover_mut() {
12786            if popover.current_signature + 1 == popover.signatures.len() {
12787                popover.current_signature = 0;
12788            } else {
12789                popover.current_signature += 1;
12790            }
12791            cx.notify();
12792        }
12793    }
12794
12795    pub fn move_to_previous_word_start(
12796        &mut self,
12797        _: &MoveToPreviousWordStart,
12798        window: &mut Window,
12799        cx: &mut Context<Self>,
12800    ) {
12801        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12802        self.change_selections(Default::default(), window, cx, |s| {
12803            s.move_cursors_with(|map, head, _| {
12804                (
12805                    movement::previous_word_start(map, head),
12806                    SelectionGoal::None,
12807                )
12808            });
12809        })
12810    }
12811
12812    pub fn move_to_previous_subword_start(
12813        &mut self,
12814        _: &MoveToPreviousSubwordStart,
12815        window: &mut Window,
12816        cx: &mut Context<Self>,
12817    ) {
12818        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12819        self.change_selections(Default::default(), window, cx, |s| {
12820            s.move_cursors_with(|map, head, _| {
12821                (
12822                    movement::previous_subword_start(map, head),
12823                    SelectionGoal::None,
12824                )
12825            });
12826        })
12827    }
12828
12829    pub fn select_to_previous_word_start(
12830        &mut self,
12831        _: &SelectToPreviousWordStart,
12832        window: &mut Window,
12833        cx: &mut Context<Self>,
12834    ) {
12835        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12836        self.change_selections(Default::default(), window, cx, |s| {
12837            s.move_heads_with(|map, head, _| {
12838                (
12839                    movement::previous_word_start(map, head),
12840                    SelectionGoal::None,
12841                )
12842            });
12843        })
12844    }
12845
12846    pub fn select_to_previous_subword_start(
12847        &mut self,
12848        _: &SelectToPreviousSubwordStart,
12849        window: &mut Window,
12850        cx: &mut Context<Self>,
12851    ) {
12852        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12853        self.change_selections(Default::default(), window, cx, |s| {
12854            s.move_heads_with(|map, head, _| {
12855                (
12856                    movement::previous_subword_start(map, head),
12857                    SelectionGoal::None,
12858                )
12859            });
12860        })
12861    }
12862
12863    pub fn delete_to_previous_word_start(
12864        &mut self,
12865        action: &DeleteToPreviousWordStart,
12866        window: &mut Window,
12867        cx: &mut Context<Self>,
12868    ) {
12869        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12870        self.transact(window, cx, |this, window, cx| {
12871            this.select_autoclose_pair(window, cx);
12872            this.change_selections(Default::default(), window, cx, |s| {
12873                s.move_with(|map, selection| {
12874                    if selection.is_empty() {
12875                        let cursor = if action.ignore_newlines {
12876                            movement::previous_word_start(map, selection.head())
12877                        } else {
12878                            movement::previous_word_start_or_newline(map, selection.head())
12879                        };
12880                        selection.set_head(cursor, SelectionGoal::None);
12881                    }
12882                });
12883            });
12884            this.insert("", window, cx);
12885        });
12886    }
12887
12888    pub fn delete_to_previous_subword_start(
12889        &mut self,
12890        _: &DeleteToPreviousSubwordStart,
12891        window: &mut Window,
12892        cx: &mut Context<Self>,
12893    ) {
12894        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12895        self.transact(window, cx, |this, window, cx| {
12896            this.select_autoclose_pair(window, cx);
12897            this.change_selections(Default::default(), window, cx, |s| {
12898                s.move_with(|map, selection| {
12899                    if selection.is_empty() {
12900                        let cursor = movement::previous_subword_start(map, selection.head());
12901                        selection.set_head(cursor, SelectionGoal::None);
12902                    }
12903                });
12904            });
12905            this.insert("", window, cx);
12906        });
12907    }
12908
12909    pub fn move_to_next_word_end(
12910        &mut self,
12911        _: &MoveToNextWordEnd,
12912        window: &mut Window,
12913        cx: &mut Context<Self>,
12914    ) {
12915        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12916        self.change_selections(Default::default(), window, cx, |s| {
12917            s.move_cursors_with(|map, head, _| {
12918                (movement::next_word_end(map, head), SelectionGoal::None)
12919            });
12920        })
12921    }
12922
12923    pub fn move_to_next_subword_end(
12924        &mut self,
12925        _: &MoveToNextSubwordEnd,
12926        window: &mut Window,
12927        cx: &mut Context<Self>,
12928    ) {
12929        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12930        self.change_selections(Default::default(), window, cx, |s| {
12931            s.move_cursors_with(|map, head, _| {
12932                (movement::next_subword_end(map, head), SelectionGoal::None)
12933            });
12934        })
12935    }
12936
12937    pub fn select_to_next_word_end(
12938        &mut self,
12939        _: &SelectToNextWordEnd,
12940        window: &mut Window,
12941        cx: &mut Context<Self>,
12942    ) {
12943        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12944        self.change_selections(Default::default(), window, cx, |s| {
12945            s.move_heads_with(|map, head, _| {
12946                (movement::next_word_end(map, head), SelectionGoal::None)
12947            });
12948        })
12949    }
12950
12951    pub fn select_to_next_subword_end(
12952        &mut self,
12953        _: &SelectToNextSubwordEnd,
12954        window: &mut Window,
12955        cx: &mut Context<Self>,
12956    ) {
12957        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12958        self.change_selections(Default::default(), window, cx, |s| {
12959            s.move_heads_with(|map, head, _| {
12960                (movement::next_subword_end(map, head), SelectionGoal::None)
12961            });
12962        })
12963    }
12964
12965    pub fn delete_to_next_word_end(
12966        &mut self,
12967        action: &DeleteToNextWordEnd,
12968        window: &mut Window,
12969        cx: &mut Context<Self>,
12970    ) {
12971        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12972        self.transact(window, cx, |this, window, cx| {
12973            this.change_selections(Default::default(), window, cx, |s| {
12974                s.move_with(|map, selection| {
12975                    if selection.is_empty() {
12976                        let cursor = if action.ignore_newlines {
12977                            movement::next_word_end(map, selection.head())
12978                        } else {
12979                            movement::next_word_end_or_newline(map, selection.head())
12980                        };
12981                        selection.set_head(cursor, SelectionGoal::None);
12982                    }
12983                });
12984            });
12985            this.insert("", window, cx);
12986        });
12987    }
12988
12989    pub fn delete_to_next_subword_end(
12990        &mut self,
12991        _: &DeleteToNextSubwordEnd,
12992        window: &mut Window,
12993        cx: &mut Context<Self>,
12994    ) {
12995        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12996        self.transact(window, cx, |this, window, cx| {
12997            this.change_selections(Default::default(), window, cx, |s| {
12998                s.move_with(|map, selection| {
12999                    if selection.is_empty() {
13000                        let cursor = movement::next_subword_end(map, selection.head());
13001                        selection.set_head(cursor, SelectionGoal::None);
13002                    }
13003                });
13004            });
13005            this.insert("", window, cx);
13006        });
13007    }
13008
13009    pub fn move_to_beginning_of_line(
13010        &mut self,
13011        action: &MoveToBeginningOfLine,
13012        window: &mut Window,
13013        cx: &mut Context<Self>,
13014    ) {
13015        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13016        self.change_selections(Default::default(), window, cx, |s| {
13017            s.move_cursors_with(|map, head, _| {
13018                (
13019                    movement::indented_line_beginning(
13020                        map,
13021                        head,
13022                        action.stop_at_soft_wraps,
13023                        action.stop_at_indent,
13024                    ),
13025                    SelectionGoal::None,
13026                )
13027            });
13028        })
13029    }
13030
13031    pub fn select_to_beginning_of_line(
13032        &mut self,
13033        action: &SelectToBeginningOfLine,
13034        window: &mut Window,
13035        cx: &mut Context<Self>,
13036    ) {
13037        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13038        self.change_selections(Default::default(), window, cx, |s| {
13039            s.move_heads_with(|map, head, _| {
13040                (
13041                    movement::indented_line_beginning(
13042                        map,
13043                        head,
13044                        action.stop_at_soft_wraps,
13045                        action.stop_at_indent,
13046                    ),
13047                    SelectionGoal::None,
13048                )
13049            });
13050        });
13051    }
13052
13053    pub fn delete_to_beginning_of_line(
13054        &mut self,
13055        action: &DeleteToBeginningOfLine,
13056        window: &mut Window,
13057        cx: &mut Context<Self>,
13058    ) {
13059        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13060        self.transact(window, cx, |this, window, cx| {
13061            this.change_selections(Default::default(), window, cx, |s| {
13062                s.move_with(|_, selection| {
13063                    selection.reversed = true;
13064                });
13065            });
13066
13067            this.select_to_beginning_of_line(
13068                &SelectToBeginningOfLine {
13069                    stop_at_soft_wraps: false,
13070                    stop_at_indent: action.stop_at_indent,
13071                },
13072                window,
13073                cx,
13074            );
13075            this.backspace(&Backspace, window, cx);
13076        });
13077    }
13078
13079    pub fn move_to_end_of_line(
13080        &mut self,
13081        action: &MoveToEndOfLine,
13082        window: &mut Window,
13083        cx: &mut Context<Self>,
13084    ) {
13085        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13086        self.change_selections(Default::default(), window, cx, |s| {
13087            s.move_cursors_with(|map, head, _| {
13088                (
13089                    movement::line_end(map, head, action.stop_at_soft_wraps),
13090                    SelectionGoal::None,
13091                )
13092            });
13093        })
13094    }
13095
13096    pub fn select_to_end_of_line(
13097        &mut self,
13098        action: &SelectToEndOfLine,
13099        window: &mut Window,
13100        cx: &mut Context<Self>,
13101    ) {
13102        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13103        self.change_selections(Default::default(), window, cx, |s| {
13104            s.move_heads_with(|map, head, _| {
13105                (
13106                    movement::line_end(map, head, action.stop_at_soft_wraps),
13107                    SelectionGoal::None,
13108                )
13109            });
13110        })
13111    }
13112
13113    pub fn delete_to_end_of_line(
13114        &mut self,
13115        _: &DeleteToEndOfLine,
13116        window: &mut Window,
13117        cx: &mut Context<Self>,
13118    ) {
13119        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13120        self.transact(window, cx, |this, window, cx| {
13121            this.select_to_end_of_line(
13122                &SelectToEndOfLine {
13123                    stop_at_soft_wraps: false,
13124                },
13125                window,
13126                cx,
13127            );
13128            this.delete(&Delete, window, cx);
13129        });
13130    }
13131
13132    pub fn cut_to_end_of_line(
13133        &mut self,
13134        _: &CutToEndOfLine,
13135        window: &mut Window,
13136        cx: &mut Context<Self>,
13137    ) {
13138        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13139        self.transact(window, cx, |this, window, cx| {
13140            this.select_to_end_of_line(
13141                &SelectToEndOfLine {
13142                    stop_at_soft_wraps: false,
13143                },
13144                window,
13145                cx,
13146            );
13147            this.cut(&Cut, window, cx);
13148        });
13149    }
13150
13151    pub fn move_to_start_of_paragraph(
13152        &mut self,
13153        _: &MoveToStartOfParagraph,
13154        window: &mut Window,
13155        cx: &mut Context<Self>,
13156    ) {
13157        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13158            cx.propagate();
13159            return;
13160        }
13161        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13162        self.change_selections(Default::default(), window, cx, |s| {
13163            s.move_with(|map, selection| {
13164                selection.collapse_to(
13165                    movement::start_of_paragraph(map, selection.head(), 1),
13166                    SelectionGoal::None,
13167                )
13168            });
13169        })
13170    }
13171
13172    pub fn move_to_end_of_paragraph(
13173        &mut self,
13174        _: &MoveToEndOfParagraph,
13175        window: &mut Window,
13176        cx: &mut Context<Self>,
13177    ) {
13178        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13179            cx.propagate();
13180            return;
13181        }
13182        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13183        self.change_selections(Default::default(), window, cx, |s| {
13184            s.move_with(|map, selection| {
13185                selection.collapse_to(
13186                    movement::end_of_paragraph(map, selection.head(), 1),
13187                    SelectionGoal::None,
13188                )
13189            });
13190        })
13191    }
13192
13193    pub fn select_to_start_of_paragraph(
13194        &mut self,
13195        _: &SelectToStartOfParagraph,
13196        window: &mut Window,
13197        cx: &mut Context<Self>,
13198    ) {
13199        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13200            cx.propagate();
13201            return;
13202        }
13203        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13204        self.change_selections(Default::default(), window, cx, |s| {
13205            s.move_heads_with(|map, head, _| {
13206                (
13207                    movement::start_of_paragraph(map, head, 1),
13208                    SelectionGoal::None,
13209                )
13210            });
13211        })
13212    }
13213
13214    pub fn select_to_end_of_paragraph(
13215        &mut self,
13216        _: &SelectToEndOfParagraph,
13217        window: &mut Window,
13218        cx: &mut Context<Self>,
13219    ) {
13220        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13221            cx.propagate();
13222            return;
13223        }
13224        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13225        self.change_selections(Default::default(), window, cx, |s| {
13226            s.move_heads_with(|map, head, _| {
13227                (
13228                    movement::end_of_paragraph(map, head, 1),
13229                    SelectionGoal::None,
13230                )
13231            });
13232        })
13233    }
13234
13235    pub fn move_to_start_of_excerpt(
13236        &mut self,
13237        _: &MoveToStartOfExcerpt,
13238        window: &mut Window,
13239        cx: &mut Context<Self>,
13240    ) {
13241        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13242            cx.propagate();
13243            return;
13244        }
13245        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13246        self.change_selections(Default::default(), window, cx, |s| {
13247            s.move_with(|map, selection| {
13248                selection.collapse_to(
13249                    movement::start_of_excerpt(
13250                        map,
13251                        selection.head(),
13252                        workspace::searchable::Direction::Prev,
13253                    ),
13254                    SelectionGoal::None,
13255                )
13256            });
13257        })
13258    }
13259
13260    pub fn move_to_start_of_next_excerpt(
13261        &mut self,
13262        _: &MoveToStartOfNextExcerpt,
13263        window: &mut Window,
13264        cx: &mut Context<Self>,
13265    ) {
13266        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13267            cx.propagate();
13268            return;
13269        }
13270
13271        self.change_selections(Default::default(), window, cx, |s| {
13272            s.move_with(|map, selection| {
13273                selection.collapse_to(
13274                    movement::start_of_excerpt(
13275                        map,
13276                        selection.head(),
13277                        workspace::searchable::Direction::Next,
13278                    ),
13279                    SelectionGoal::None,
13280                )
13281            });
13282        })
13283    }
13284
13285    pub fn move_to_end_of_excerpt(
13286        &mut self,
13287        _: &MoveToEndOfExcerpt,
13288        window: &mut Window,
13289        cx: &mut Context<Self>,
13290    ) {
13291        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13292            cx.propagate();
13293            return;
13294        }
13295        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13296        self.change_selections(Default::default(), window, cx, |s| {
13297            s.move_with(|map, selection| {
13298                selection.collapse_to(
13299                    movement::end_of_excerpt(
13300                        map,
13301                        selection.head(),
13302                        workspace::searchable::Direction::Next,
13303                    ),
13304                    SelectionGoal::None,
13305                )
13306            });
13307        })
13308    }
13309
13310    pub fn move_to_end_of_previous_excerpt(
13311        &mut self,
13312        _: &MoveToEndOfPreviousExcerpt,
13313        window: &mut Window,
13314        cx: &mut Context<Self>,
13315    ) {
13316        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13317            cx.propagate();
13318            return;
13319        }
13320        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13321        self.change_selections(Default::default(), window, cx, |s| {
13322            s.move_with(|map, selection| {
13323                selection.collapse_to(
13324                    movement::end_of_excerpt(
13325                        map,
13326                        selection.head(),
13327                        workspace::searchable::Direction::Prev,
13328                    ),
13329                    SelectionGoal::None,
13330                )
13331            });
13332        })
13333    }
13334
13335    pub fn select_to_start_of_excerpt(
13336        &mut self,
13337        _: &SelectToStartOfExcerpt,
13338        window: &mut Window,
13339        cx: &mut Context<Self>,
13340    ) {
13341        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13342            cx.propagate();
13343            return;
13344        }
13345        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13346        self.change_selections(Default::default(), window, cx, |s| {
13347            s.move_heads_with(|map, head, _| {
13348                (
13349                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13350                    SelectionGoal::None,
13351                )
13352            });
13353        })
13354    }
13355
13356    pub fn select_to_start_of_next_excerpt(
13357        &mut self,
13358        _: &SelectToStartOfNextExcerpt,
13359        window: &mut Window,
13360        cx: &mut Context<Self>,
13361    ) {
13362        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13363            cx.propagate();
13364            return;
13365        }
13366        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13367        self.change_selections(Default::default(), window, cx, |s| {
13368            s.move_heads_with(|map, head, _| {
13369                (
13370                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13371                    SelectionGoal::None,
13372                )
13373            });
13374        })
13375    }
13376
13377    pub fn select_to_end_of_excerpt(
13378        &mut self,
13379        _: &SelectToEndOfExcerpt,
13380        window: &mut Window,
13381        cx: &mut Context<Self>,
13382    ) {
13383        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13384            cx.propagate();
13385            return;
13386        }
13387        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13388        self.change_selections(Default::default(), window, cx, |s| {
13389            s.move_heads_with(|map, head, _| {
13390                (
13391                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13392                    SelectionGoal::None,
13393                )
13394            });
13395        })
13396    }
13397
13398    pub fn select_to_end_of_previous_excerpt(
13399        &mut self,
13400        _: &SelectToEndOfPreviousExcerpt,
13401        window: &mut Window,
13402        cx: &mut Context<Self>,
13403    ) {
13404        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13405            cx.propagate();
13406            return;
13407        }
13408        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13409        self.change_selections(Default::default(), window, cx, |s| {
13410            s.move_heads_with(|map, head, _| {
13411                (
13412                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13413                    SelectionGoal::None,
13414                )
13415            });
13416        })
13417    }
13418
13419    pub fn move_to_beginning(
13420        &mut self,
13421        _: &MoveToBeginning,
13422        window: &mut Window,
13423        cx: &mut Context<Self>,
13424    ) {
13425        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13426            cx.propagate();
13427            return;
13428        }
13429        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13430        self.change_selections(Default::default(), window, cx, |s| {
13431            s.select_ranges(vec![0..0]);
13432        });
13433    }
13434
13435    pub fn select_to_beginning(
13436        &mut self,
13437        _: &SelectToBeginning,
13438        window: &mut Window,
13439        cx: &mut Context<Self>,
13440    ) {
13441        let mut selection = self.selections.last::<Point>(cx);
13442        selection.set_head(Point::zero(), SelectionGoal::None);
13443        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13444        self.change_selections(Default::default(), window, cx, |s| {
13445            s.select(vec![selection]);
13446        });
13447    }
13448
13449    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13450        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13451            cx.propagate();
13452            return;
13453        }
13454        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13455        let cursor = self.buffer.read(cx).read(cx).len();
13456        self.change_selections(Default::default(), window, cx, |s| {
13457            s.select_ranges(vec![cursor..cursor])
13458        });
13459    }
13460
13461    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13462        self.nav_history = nav_history;
13463    }
13464
13465    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13466        self.nav_history.as_ref()
13467    }
13468
13469    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13470        self.push_to_nav_history(
13471            self.selections.newest_anchor().head(),
13472            None,
13473            false,
13474            true,
13475            cx,
13476        );
13477    }
13478
13479    fn push_to_nav_history(
13480        &mut self,
13481        cursor_anchor: Anchor,
13482        new_position: Option<Point>,
13483        is_deactivate: bool,
13484        always: bool,
13485        cx: &mut Context<Self>,
13486    ) {
13487        if let Some(nav_history) = self.nav_history.as_mut() {
13488            let buffer = self.buffer.read(cx).read(cx);
13489            let cursor_position = cursor_anchor.to_point(&buffer);
13490            let scroll_state = self.scroll_manager.anchor();
13491            let scroll_top_row = scroll_state.top_row(&buffer);
13492            drop(buffer);
13493
13494            if let Some(new_position) = new_position {
13495                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13496                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13497                    return;
13498                }
13499            }
13500
13501            nav_history.push(
13502                Some(NavigationData {
13503                    cursor_anchor,
13504                    cursor_position,
13505                    scroll_anchor: scroll_state,
13506                    scroll_top_row,
13507                }),
13508                cx,
13509            );
13510            cx.emit(EditorEvent::PushedToNavHistory {
13511                anchor: cursor_anchor,
13512                is_deactivate,
13513            })
13514        }
13515    }
13516
13517    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13518        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13519        let buffer = self.buffer.read(cx).snapshot(cx);
13520        let mut selection = self.selections.first::<usize>(cx);
13521        selection.set_head(buffer.len(), SelectionGoal::None);
13522        self.change_selections(Default::default(), window, cx, |s| {
13523            s.select(vec![selection]);
13524        });
13525    }
13526
13527    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13528        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13529        let end = self.buffer.read(cx).read(cx).len();
13530        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13531            s.select_ranges(vec![0..end]);
13532        });
13533    }
13534
13535    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13536        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13537        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13538        let mut selections = self.selections.all::<Point>(cx);
13539        let max_point = display_map.buffer_snapshot.max_point();
13540        for selection in &mut selections {
13541            let rows = selection.spanned_rows(true, &display_map);
13542            selection.start = Point::new(rows.start.0, 0);
13543            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13544            selection.reversed = false;
13545        }
13546        self.change_selections(Default::default(), window, cx, |s| {
13547            s.select(selections);
13548        });
13549    }
13550
13551    pub fn split_selection_into_lines(
13552        &mut self,
13553        _: &SplitSelectionIntoLines,
13554        window: &mut Window,
13555        cx: &mut Context<Self>,
13556    ) {
13557        let selections = self
13558            .selections
13559            .all::<Point>(cx)
13560            .into_iter()
13561            .map(|selection| selection.start..selection.end)
13562            .collect::<Vec<_>>();
13563        self.unfold_ranges(&selections, true, true, cx);
13564
13565        let mut new_selection_ranges = Vec::new();
13566        {
13567            let buffer = self.buffer.read(cx).read(cx);
13568            for selection in selections {
13569                for row in selection.start.row..selection.end.row {
13570                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13571                    new_selection_ranges.push(cursor..cursor);
13572                }
13573
13574                let is_multiline_selection = selection.start.row != selection.end.row;
13575                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13576                // so this action feels more ergonomic when paired with other selection operations
13577                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13578                if !should_skip_last {
13579                    new_selection_ranges.push(selection.end..selection.end);
13580                }
13581            }
13582        }
13583        self.change_selections(Default::default(), window, cx, |s| {
13584            s.select_ranges(new_selection_ranges);
13585        });
13586    }
13587
13588    pub fn add_selection_above(
13589        &mut self,
13590        _: &AddSelectionAbove,
13591        window: &mut Window,
13592        cx: &mut Context<Self>,
13593    ) {
13594        self.add_selection(true, window, cx);
13595    }
13596
13597    pub fn add_selection_below(
13598        &mut self,
13599        _: &AddSelectionBelow,
13600        window: &mut Window,
13601        cx: &mut Context<Self>,
13602    ) {
13603        self.add_selection(false, window, cx);
13604    }
13605
13606    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13607        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13608
13609        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13610        let all_selections = self.selections.all::<Point>(cx);
13611        let text_layout_details = self.text_layout_details(window);
13612
13613        let (mut columnar_selections, new_selections_to_columnarize) = {
13614            if let Some(state) = self.add_selections_state.as_ref() {
13615                let columnar_selection_ids: HashSet<_> = state
13616                    .groups
13617                    .iter()
13618                    .flat_map(|group| group.stack.iter())
13619                    .copied()
13620                    .collect();
13621
13622                all_selections
13623                    .into_iter()
13624                    .partition(|s| columnar_selection_ids.contains(&s.id))
13625            } else {
13626                (Vec::new(), all_selections)
13627            }
13628        };
13629
13630        let mut state = self
13631            .add_selections_state
13632            .take()
13633            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13634
13635        for selection in new_selections_to_columnarize {
13636            let range = selection.display_range(&display_map).sorted();
13637            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13638            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13639            let positions = start_x.min(end_x)..start_x.max(end_x);
13640            let mut stack = Vec::new();
13641            for row in range.start.row().0..=range.end.row().0 {
13642                if let Some(selection) = self.selections.build_columnar_selection(
13643                    &display_map,
13644                    DisplayRow(row),
13645                    &positions,
13646                    selection.reversed,
13647                    &text_layout_details,
13648                ) {
13649                    stack.push(selection.id);
13650                    columnar_selections.push(selection);
13651                }
13652            }
13653            if !stack.is_empty() {
13654                if above {
13655                    stack.reverse();
13656                }
13657                state.groups.push(AddSelectionsGroup { above, stack });
13658            }
13659        }
13660
13661        let mut final_selections = Vec::new();
13662        let end_row = if above {
13663            DisplayRow(0)
13664        } else {
13665            display_map.max_point().row()
13666        };
13667
13668        let mut last_added_item_per_group = HashMap::default();
13669        for group in state.groups.iter_mut() {
13670            if let Some(last_id) = group.stack.last() {
13671                last_added_item_per_group.insert(*last_id, group);
13672            }
13673        }
13674
13675        for selection in columnar_selections {
13676            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13677                if above == group.above {
13678                    let range = selection.display_range(&display_map).sorted();
13679                    debug_assert_eq!(range.start.row(), range.end.row());
13680                    let mut row = range.start.row();
13681                    let positions =
13682                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13683                            px(start)..px(end)
13684                        } else {
13685                            let start_x =
13686                                display_map.x_for_display_point(range.start, &text_layout_details);
13687                            let end_x =
13688                                display_map.x_for_display_point(range.end, &text_layout_details);
13689                            start_x.min(end_x)..start_x.max(end_x)
13690                        };
13691
13692                    let mut maybe_new_selection = None;
13693                    while row != end_row {
13694                        if above {
13695                            row.0 -= 1;
13696                        } else {
13697                            row.0 += 1;
13698                        }
13699                        if let Some(new_selection) = self.selections.build_columnar_selection(
13700                            &display_map,
13701                            row,
13702                            &positions,
13703                            selection.reversed,
13704                            &text_layout_details,
13705                        ) {
13706                            maybe_new_selection = Some(new_selection);
13707                            break;
13708                        }
13709                    }
13710
13711                    if let Some(new_selection) = maybe_new_selection {
13712                        group.stack.push(new_selection.id);
13713                        if above {
13714                            final_selections.push(new_selection);
13715                            final_selections.push(selection);
13716                        } else {
13717                            final_selections.push(selection);
13718                            final_selections.push(new_selection);
13719                        }
13720                    } else {
13721                        final_selections.push(selection);
13722                    }
13723                } else {
13724                    group.stack.pop();
13725                }
13726            } else {
13727                final_selections.push(selection);
13728            }
13729        }
13730
13731        self.change_selections(Default::default(), window, cx, |s| {
13732            s.select(final_selections);
13733        });
13734
13735        let final_selection_ids: HashSet<_> = self
13736            .selections
13737            .all::<Point>(cx)
13738            .iter()
13739            .map(|s| s.id)
13740            .collect();
13741        state.groups.retain_mut(|group| {
13742            // selections might get merged above so we remove invalid items from stacks
13743            group.stack.retain(|id| final_selection_ids.contains(id));
13744
13745            // single selection in stack can be treated as initial state
13746            group.stack.len() > 1
13747        });
13748
13749        if !state.groups.is_empty() {
13750            self.add_selections_state = Some(state);
13751        }
13752    }
13753
13754    fn select_match_ranges(
13755        &mut self,
13756        range: Range<usize>,
13757        reversed: bool,
13758        replace_newest: bool,
13759        auto_scroll: Option<Autoscroll>,
13760        window: &mut Window,
13761        cx: &mut Context<Editor>,
13762    ) {
13763        self.unfold_ranges(
13764            std::slice::from_ref(&range),
13765            false,
13766            auto_scroll.is_some(),
13767            cx,
13768        );
13769        let effects = if let Some(scroll) = auto_scroll {
13770            SelectionEffects::scroll(scroll)
13771        } else {
13772            SelectionEffects::no_scroll()
13773        };
13774        self.change_selections(effects, window, cx, |s| {
13775            if replace_newest {
13776                s.delete(s.newest_anchor().id);
13777            }
13778            if reversed {
13779                s.insert_range(range.end..range.start);
13780            } else {
13781                s.insert_range(range);
13782            }
13783        });
13784    }
13785
13786    pub fn select_next_match_internal(
13787        &mut self,
13788        display_map: &DisplaySnapshot,
13789        replace_newest: bool,
13790        autoscroll: Option<Autoscroll>,
13791        window: &mut Window,
13792        cx: &mut Context<Self>,
13793    ) -> Result<()> {
13794        let buffer = &display_map.buffer_snapshot;
13795        let mut selections = self.selections.all::<usize>(cx);
13796        if let Some(mut select_next_state) = self.select_next_state.take() {
13797            let query = &select_next_state.query;
13798            if !select_next_state.done {
13799                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13800                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13801                let mut next_selected_range = None;
13802
13803                let bytes_after_last_selection =
13804                    buffer.bytes_in_range(last_selection.end..buffer.len());
13805                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13806                let query_matches = query
13807                    .stream_find_iter(bytes_after_last_selection)
13808                    .map(|result| (last_selection.end, result))
13809                    .chain(
13810                        query
13811                            .stream_find_iter(bytes_before_first_selection)
13812                            .map(|result| (0, result)),
13813                    );
13814
13815                for (start_offset, query_match) in query_matches {
13816                    let query_match = query_match.unwrap(); // can only fail due to I/O
13817                    let offset_range =
13818                        start_offset + query_match.start()..start_offset + query_match.end();
13819
13820                    if !select_next_state.wordwise
13821                        || (!buffer.is_inside_word(offset_range.start, false)
13822                            && !buffer.is_inside_word(offset_range.end, false))
13823                    {
13824                        // TODO: This is n^2, because we might check all the selections
13825                        if !selections
13826                            .iter()
13827                            .any(|selection| selection.range().overlaps(&offset_range))
13828                        {
13829                            next_selected_range = Some(offset_range);
13830                            break;
13831                        }
13832                    }
13833                }
13834
13835                if let Some(next_selected_range) = next_selected_range {
13836                    self.select_match_ranges(
13837                        next_selected_range,
13838                        last_selection.reversed,
13839                        replace_newest,
13840                        autoscroll,
13841                        window,
13842                        cx,
13843                    );
13844                } else {
13845                    select_next_state.done = true;
13846                }
13847            }
13848
13849            self.select_next_state = Some(select_next_state);
13850        } else {
13851            let mut only_carets = true;
13852            let mut same_text_selected = true;
13853            let mut selected_text = None;
13854
13855            let mut selections_iter = selections.iter().peekable();
13856            while let Some(selection) = selections_iter.next() {
13857                if selection.start != selection.end {
13858                    only_carets = false;
13859                }
13860
13861                if same_text_selected {
13862                    if selected_text.is_none() {
13863                        selected_text =
13864                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13865                    }
13866
13867                    if let Some(next_selection) = selections_iter.peek() {
13868                        if next_selection.range().len() == selection.range().len() {
13869                            let next_selected_text = buffer
13870                                .text_for_range(next_selection.range())
13871                                .collect::<String>();
13872                            if Some(next_selected_text) != selected_text {
13873                                same_text_selected = false;
13874                                selected_text = None;
13875                            }
13876                        } else {
13877                            same_text_selected = false;
13878                            selected_text = None;
13879                        }
13880                    }
13881                }
13882            }
13883
13884            if only_carets {
13885                for selection in &mut selections {
13886                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13887                    selection.start = word_range.start;
13888                    selection.end = word_range.end;
13889                    selection.goal = SelectionGoal::None;
13890                    selection.reversed = false;
13891                    self.select_match_ranges(
13892                        selection.start..selection.end,
13893                        selection.reversed,
13894                        replace_newest,
13895                        autoscroll,
13896                        window,
13897                        cx,
13898                    );
13899                }
13900
13901                if selections.len() == 1 {
13902                    let selection = selections
13903                        .last()
13904                        .expect("ensured that there's only one selection");
13905                    let query = buffer
13906                        .text_for_range(selection.start..selection.end)
13907                        .collect::<String>();
13908                    let is_empty = query.is_empty();
13909                    let select_state = SelectNextState {
13910                        query: AhoCorasick::new(&[query])?,
13911                        wordwise: true,
13912                        done: is_empty,
13913                    };
13914                    self.select_next_state = Some(select_state);
13915                } else {
13916                    self.select_next_state = None;
13917                }
13918            } else if let Some(selected_text) = selected_text {
13919                self.select_next_state = Some(SelectNextState {
13920                    query: AhoCorasick::new(&[selected_text])?,
13921                    wordwise: false,
13922                    done: false,
13923                });
13924                self.select_next_match_internal(
13925                    display_map,
13926                    replace_newest,
13927                    autoscroll,
13928                    window,
13929                    cx,
13930                )?;
13931            }
13932        }
13933        Ok(())
13934    }
13935
13936    pub fn select_all_matches(
13937        &mut self,
13938        _action: &SelectAllMatches,
13939        window: &mut Window,
13940        cx: &mut Context<Self>,
13941    ) -> Result<()> {
13942        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13943
13944        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13945
13946        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13947        let Some(select_next_state) = self.select_next_state.as_mut() else {
13948            return Ok(());
13949        };
13950        if select_next_state.done {
13951            return Ok(());
13952        }
13953
13954        let mut new_selections = Vec::new();
13955
13956        let reversed = self.selections.oldest::<usize>(cx).reversed;
13957        let buffer = &display_map.buffer_snapshot;
13958        let query_matches = select_next_state
13959            .query
13960            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13961
13962        for query_match in query_matches.into_iter() {
13963            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13964            let offset_range = if reversed {
13965                query_match.end()..query_match.start()
13966            } else {
13967                query_match.start()..query_match.end()
13968            };
13969
13970            if !select_next_state.wordwise
13971                || (!buffer.is_inside_word(offset_range.start, false)
13972                    && !buffer.is_inside_word(offset_range.end, false))
13973            {
13974                new_selections.push(offset_range.start..offset_range.end);
13975            }
13976        }
13977
13978        select_next_state.done = true;
13979
13980        if new_selections.is_empty() {
13981            log::error!("bug: new_selections is empty in select_all_matches");
13982            return Ok(());
13983        }
13984
13985        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13986        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
13987            selections.select_ranges(new_selections)
13988        });
13989
13990        Ok(())
13991    }
13992
13993    pub fn select_next(
13994        &mut self,
13995        action: &SelectNext,
13996        window: &mut Window,
13997        cx: &mut Context<Self>,
13998    ) -> Result<()> {
13999        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14000        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14001        self.select_next_match_internal(
14002            &display_map,
14003            action.replace_newest,
14004            Some(Autoscroll::newest()),
14005            window,
14006            cx,
14007        )?;
14008        Ok(())
14009    }
14010
14011    pub fn select_previous(
14012        &mut self,
14013        action: &SelectPrevious,
14014        window: &mut Window,
14015        cx: &mut Context<Self>,
14016    ) -> Result<()> {
14017        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14018        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14019        let buffer = &display_map.buffer_snapshot;
14020        let mut selections = self.selections.all::<usize>(cx);
14021        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14022            let query = &select_prev_state.query;
14023            if !select_prev_state.done {
14024                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14025                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14026                let mut next_selected_range = None;
14027                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14028                let bytes_before_last_selection =
14029                    buffer.reversed_bytes_in_range(0..last_selection.start);
14030                let bytes_after_first_selection =
14031                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14032                let query_matches = query
14033                    .stream_find_iter(bytes_before_last_selection)
14034                    .map(|result| (last_selection.start, result))
14035                    .chain(
14036                        query
14037                            .stream_find_iter(bytes_after_first_selection)
14038                            .map(|result| (buffer.len(), result)),
14039                    );
14040                for (end_offset, query_match) in query_matches {
14041                    let query_match = query_match.unwrap(); // can only fail due to I/O
14042                    let offset_range =
14043                        end_offset - query_match.end()..end_offset - query_match.start();
14044
14045                    if !select_prev_state.wordwise
14046                        || (!buffer.is_inside_word(offset_range.start, false)
14047                            && !buffer.is_inside_word(offset_range.end, false))
14048                    {
14049                        next_selected_range = Some(offset_range);
14050                        break;
14051                    }
14052                }
14053
14054                if let Some(next_selected_range) = next_selected_range {
14055                    self.select_match_ranges(
14056                        next_selected_range,
14057                        last_selection.reversed,
14058                        action.replace_newest,
14059                        Some(Autoscroll::newest()),
14060                        window,
14061                        cx,
14062                    );
14063                } else {
14064                    select_prev_state.done = true;
14065                }
14066            }
14067
14068            self.select_prev_state = Some(select_prev_state);
14069        } else {
14070            let mut only_carets = true;
14071            let mut same_text_selected = true;
14072            let mut selected_text = None;
14073
14074            let mut selections_iter = selections.iter().peekable();
14075            while let Some(selection) = selections_iter.next() {
14076                if selection.start != selection.end {
14077                    only_carets = false;
14078                }
14079
14080                if same_text_selected {
14081                    if selected_text.is_none() {
14082                        selected_text =
14083                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14084                    }
14085
14086                    if let Some(next_selection) = selections_iter.peek() {
14087                        if next_selection.range().len() == selection.range().len() {
14088                            let next_selected_text = buffer
14089                                .text_for_range(next_selection.range())
14090                                .collect::<String>();
14091                            if Some(next_selected_text) != selected_text {
14092                                same_text_selected = false;
14093                                selected_text = None;
14094                            }
14095                        } else {
14096                            same_text_selected = false;
14097                            selected_text = None;
14098                        }
14099                    }
14100                }
14101            }
14102
14103            if only_carets {
14104                for selection in &mut selections {
14105                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14106                    selection.start = word_range.start;
14107                    selection.end = word_range.end;
14108                    selection.goal = SelectionGoal::None;
14109                    selection.reversed = false;
14110                    self.select_match_ranges(
14111                        selection.start..selection.end,
14112                        selection.reversed,
14113                        action.replace_newest,
14114                        Some(Autoscroll::newest()),
14115                        window,
14116                        cx,
14117                    );
14118                }
14119                if selections.len() == 1 {
14120                    let selection = selections
14121                        .last()
14122                        .expect("ensured that there's only one selection");
14123                    let query = buffer
14124                        .text_for_range(selection.start..selection.end)
14125                        .collect::<String>();
14126                    let is_empty = query.is_empty();
14127                    let select_state = SelectNextState {
14128                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14129                        wordwise: true,
14130                        done: is_empty,
14131                    };
14132                    self.select_prev_state = Some(select_state);
14133                } else {
14134                    self.select_prev_state = None;
14135                }
14136            } else if let Some(selected_text) = selected_text {
14137                self.select_prev_state = Some(SelectNextState {
14138                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14139                    wordwise: false,
14140                    done: false,
14141                });
14142                self.select_previous(action, window, cx)?;
14143            }
14144        }
14145        Ok(())
14146    }
14147
14148    pub fn find_next_match(
14149        &mut self,
14150        _: &FindNextMatch,
14151        window: &mut Window,
14152        cx: &mut Context<Self>,
14153    ) -> Result<()> {
14154        let selections = self.selections.disjoint_anchors();
14155        match selections.first() {
14156            Some(first) if selections.len() >= 2 => {
14157                self.change_selections(Default::default(), window, cx, |s| {
14158                    s.select_ranges([first.range()]);
14159                });
14160            }
14161            _ => self.select_next(
14162                &SelectNext {
14163                    replace_newest: true,
14164                },
14165                window,
14166                cx,
14167            )?,
14168        }
14169        Ok(())
14170    }
14171
14172    pub fn find_previous_match(
14173        &mut self,
14174        _: &FindPreviousMatch,
14175        window: &mut Window,
14176        cx: &mut Context<Self>,
14177    ) -> Result<()> {
14178        let selections = self.selections.disjoint_anchors();
14179        match selections.last() {
14180            Some(last) if selections.len() >= 2 => {
14181                self.change_selections(Default::default(), window, cx, |s| {
14182                    s.select_ranges([last.range()]);
14183                });
14184            }
14185            _ => self.select_previous(
14186                &SelectPrevious {
14187                    replace_newest: true,
14188                },
14189                window,
14190                cx,
14191            )?,
14192        }
14193        Ok(())
14194    }
14195
14196    pub fn toggle_comments(
14197        &mut self,
14198        action: &ToggleComments,
14199        window: &mut Window,
14200        cx: &mut Context<Self>,
14201    ) {
14202        if self.read_only(cx) {
14203            return;
14204        }
14205        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14206        let text_layout_details = &self.text_layout_details(window);
14207        self.transact(window, cx, |this, window, cx| {
14208            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14209            let mut edits = Vec::new();
14210            let mut selection_edit_ranges = Vec::new();
14211            let mut last_toggled_row = None;
14212            let snapshot = this.buffer.read(cx).read(cx);
14213            let empty_str: Arc<str> = Arc::default();
14214            let mut suffixes_inserted = Vec::new();
14215            let ignore_indent = action.ignore_indent;
14216
14217            fn comment_prefix_range(
14218                snapshot: &MultiBufferSnapshot,
14219                row: MultiBufferRow,
14220                comment_prefix: &str,
14221                comment_prefix_whitespace: &str,
14222                ignore_indent: bool,
14223            ) -> Range<Point> {
14224                let indent_size = if ignore_indent {
14225                    0
14226                } else {
14227                    snapshot.indent_size_for_line(row).len
14228                };
14229
14230                let start = Point::new(row.0, indent_size);
14231
14232                let mut line_bytes = snapshot
14233                    .bytes_in_range(start..snapshot.max_point())
14234                    .flatten()
14235                    .copied();
14236
14237                // If this line currently begins with the line comment prefix, then record
14238                // the range containing the prefix.
14239                if line_bytes
14240                    .by_ref()
14241                    .take(comment_prefix.len())
14242                    .eq(comment_prefix.bytes())
14243                {
14244                    // Include any whitespace that matches the comment prefix.
14245                    let matching_whitespace_len = line_bytes
14246                        .zip(comment_prefix_whitespace.bytes())
14247                        .take_while(|(a, b)| a == b)
14248                        .count() as u32;
14249                    let end = Point::new(
14250                        start.row,
14251                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14252                    );
14253                    start..end
14254                } else {
14255                    start..start
14256                }
14257            }
14258
14259            fn comment_suffix_range(
14260                snapshot: &MultiBufferSnapshot,
14261                row: MultiBufferRow,
14262                comment_suffix: &str,
14263                comment_suffix_has_leading_space: bool,
14264            ) -> Range<Point> {
14265                let end = Point::new(row.0, snapshot.line_len(row));
14266                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14267
14268                let mut line_end_bytes = snapshot
14269                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14270                    .flatten()
14271                    .copied();
14272
14273                let leading_space_len = if suffix_start_column > 0
14274                    && line_end_bytes.next() == Some(b' ')
14275                    && comment_suffix_has_leading_space
14276                {
14277                    1
14278                } else {
14279                    0
14280                };
14281
14282                // If this line currently begins with the line comment prefix, then record
14283                // the range containing the prefix.
14284                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14285                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14286                    start..end
14287                } else {
14288                    end..end
14289                }
14290            }
14291
14292            // TODO: Handle selections that cross excerpts
14293            for selection in &mut selections {
14294                let start_column = snapshot
14295                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14296                    .len;
14297                let language = if let Some(language) =
14298                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14299                {
14300                    language
14301                } else {
14302                    continue;
14303                };
14304
14305                selection_edit_ranges.clear();
14306
14307                // If multiple selections contain a given row, avoid processing that
14308                // row more than once.
14309                let mut start_row = MultiBufferRow(selection.start.row);
14310                if last_toggled_row == Some(start_row) {
14311                    start_row = start_row.next_row();
14312                }
14313                let end_row =
14314                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14315                        MultiBufferRow(selection.end.row - 1)
14316                    } else {
14317                        MultiBufferRow(selection.end.row)
14318                    };
14319                last_toggled_row = Some(end_row);
14320
14321                if start_row > end_row {
14322                    continue;
14323                }
14324
14325                // If the language has line comments, toggle those.
14326                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14327
14328                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14329                if ignore_indent {
14330                    full_comment_prefixes = full_comment_prefixes
14331                        .into_iter()
14332                        .map(|s| Arc::from(s.trim_end()))
14333                        .collect();
14334                }
14335
14336                if !full_comment_prefixes.is_empty() {
14337                    let first_prefix = full_comment_prefixes
14338                        .first()
14339                        .expect("prefixes is non-empty");
14340                    let prefix_trimmed_lengths = full_comment_prefixes
14341                        .iter()
14342                        .map(|p| p.trim_end_matches(' ').len())
14343                        .collect::<SmallVec<[usize; 4]>>();
14344
14345                    let mut all_selection_lines_are_comments = true;
14346
14347                    for row in start_row.0..=end_row.0 {
14348                        let row = MultiBufferRow(row);
14349                        if start_row < end_row && snapshot.is_line_blank(row) {
14350                            continue;
14351                        }
14352
14353                        let prefix_range = full_comment_prefixes
14354                            .iter()
14355                            .zip(prefix_trimmed_lengths.iter().copied())
14356                            .map(|(prefix, trimmed_prefix_len)| {
14357                                comment_prefix_range(
14358                                    snapshot.deref(),
14359                                    row,
14360                                    &prefix[..trimmed_prefix_len],
14361                                    &prefix[trimmed_prefix_len..],
14362                                    ignore_indent,
14363                                )
14364                            })
14365                            .max_by_key(|range| range.end.column - range.start.column)
14366                            .expect("prefixes is non-empty");
14367
14368                        if prefix_range.is_empty() {
14369                            all_selection_lines_are_comments = false;
14370                        }
14371
14372                        selection_edit_ranges.push(prefix_range);
14373                    }
14374
14375                    if all_selection_lines_are_comments {
14376                        edits.extend(
14377                            selection_edit_ranges
14378                                .iter()
14379                                .cloned()
14380                                .map(|range| (range, empty_str.clone())),
14381                        );
14382                    } else {
14383                        let min_column = selection_edit_ranges
14384                            .iter()
14385                            .map(|range| range.start.column)
14386                            .min()
14387                            .unwrap_or(0);
14388                        edits.extend(selection_edit_ranges.iter().map(|range| {
14389                            let position = Point::new(range.start.row, min_column);
14390                            (position..position, first_prefix.clone())
14391                        }));
14392                    }
14393                } else if let Some(BlockCommentConfig {
14394                    start: full_comment_prefix,
14395                    end: comment_suffix,
14396                    ..
14397                }) = language.block_comment()
14398                {
14399                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14400                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14401                    let prefix_range = comment_prefix_range(
14402                        snapshot.deref(),
14403                        start_row,
14404                        comment_prefix,
14405                        comment_prefix_whitespace,
14406                        ignore_indent,
14407                    );
14408                    let suffix_range = comment_suffix_range(
14409                        snapshot.deref(),
14410                        end_row,
14411                        comment_suffix.trim_start_matches(' '),
14412                        comment_suffix.starts_with(' '),
14413                    );
14414
14415                    if prefix_range.is_empty() || suffix_range.is_empty() {
14416                        edits.push((
14417                            prefix_range.start..prefix_range.start,
14418                            full_comment_prefix.clone(),
14419                        ));
14420                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14421                        suffixes_inserted.push((end_row, comment_suffix.len()));
14422                    } else {
14423                        edits.push((prefix_range, empty_str.clone()));
14424                        edits.push((suffix_range, empty_str.clone()));
14425                    }
14426                } else {
14427                    continue;
14428                }
14429            }
14430
14431            drop(snapshot);
14432            this.buffer.update(cx, |buffer, cx| {
14433                buffer.edit(edits, None, cx);
14434            });
14435
14436            // Adjust selections so that they end before any comment suffixes that
14437            // were inserted.
14438            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14439            let mut selections = this.selections.all::<Point>(cx);
14440            let snapshot = this.buffer.read(cx).read(cx);
14441            for selection in &mut selections {
14442                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14443                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14444                        Ordering::Less => {
14445                            suffixes_inserted.next();
14446                            continue;
14447                        }
14448                        Ordering::Greater => break,
14449                        Ordering::Equal => {
14450                            if selection.end.column == snapshot.line_len(row) {
14451                                if selection.is_empty() {
14452                                    selection.start.column -= suffix_len as u32;
14453                                }
14454                                selection.end.column -= suffix_len as u32;
14455                            }
14456                            break;
14457                        }
14458                    }
14459                }
14460            }
14461
14462            drop(snapshot);
14463            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14464
14465            let selections = this.selections.all::<Point>(cx);
14466            let selections_on_single_row = selections.windows(2).all(|selections| {
14467                selections[0].start.row == selections[1].start.row
14468                    && selections[0].end.row == selections[1].end.row
14469                    && selections[0].start.row == selections[0].end.row
14470            });
14471            let selections_selecting = selections
14472                .iter()
14473                .any(|selection| selection.start != selection.end);
14474            let advance_downwards = action.advance_downwards
14475                && selections_on_single_row
14476                && !selections_selecting
14477                && !matches!(this.mode, EditorMode::SingleLine { .. });
14478
14479            if advance_downwards {
14480                let snapshot = this.buffer.read(cx).snapshot(cx);
14481
14482                this.change_selections(Default::default(), window, cx, |s| {
14483                    s.move_cursors_with(|display_snapshot, display_point, _| {
14484                        let mut point = display_point.to_point(display_snapshot);
14485                        point.row += 1;
14486                        point = snapshot.clip_point(point, Bias::Left);
14487                        let display_point = point.to_display_point(display_snapshot);
14488                        let goal = SelectionGoal::HorizontalPosition(
14489                            display_snapshot
14490                                .x_for_display_point(display_point, text_layout_details)
14491                                .into(),
14492                        );
14493                        (display_point, goal)
14494                    })
14495                });
14496            }
14497        });
14498    }
14499
14500    pub fn select_enclosing_symbol(
14501        &mut self,
14502        _: &SelectEnclosingSymbol,
14503        window: &mut Window,
14504        cx: &mut Context<Self>,
14505    ) {
14506        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14507
14508        let buffer = self.buffer.read(cx).snapshot(cx);
14509        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14510
14511        fn update_selection(
14512            selection: &Selection<usize>,
14513            buffer_snap: &MultiBufferSnapshot,
14514        ) -> Option<Selection<usize>> {
14515            let cursor = selection.head();
14516            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14517            for symbol in symbols.iter().rev() {
14518                let start = symbol.range.start.to_offset(buffer_snap);
14519                let end = symbol.range.end.to_offset(buffer_snap);
14520                let new_range = start..end;
14521                if start < selection.start || end > selection.end {
14522                    return Some(Selection {
14523                        id: selection.id,
14524                        start: new_range.start,
14525                        end: new_range.end,
14526                        goal: SelectionGoal::None,
14527                        reversed: selection.reversed,
14528                    });
14529                }
14530            }
14531            None
14532        }
14533
14534        let mut selected_larger_symbol = false;
14535        let new_selections = old_selections
14536            .iter()
14537            .map(|selection| match update_selection(selection, &buffer) {
14538                Some(new_selection) => {
14539                    if new_selection.range() != selection.range() {
14540                        selected_larger_symbol = true;
14541                    }
14542                    new_selection
14543                }
14544                None => selection.clone(),
14545            })
14546            .collect::<Vec<_>>();
14547
14548        if selected_larger_symbol {
14549            self.change_selections(Default::default(), window, cx, |s| {
14550                s.select(new_selections);
14551            });
14552        }
14553    }
14554
14555    pub fn select_larger_syntax_node(
14556        &mut self,
14557        _: &SelectLargerSyntaxNode,
14558        window: &mut Window,
14559        cx: &mut Context<Self>,
14560    ) {
14561        let Some(visible_row_count) = self.visible_row_count() else {
14562            return;
14563        };
14564        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14565        if old_selections.is_empty() {
14566            return;
14567        }
14568
14569        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14570
14571        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14572        let buffer = self.buffer.read(cx).snapshot(cx);
14573
14574        let mut selected_larger_node = false;
14575        let mut new_selections = old_selections
14576            .iter()
14577            .map(|selection| {
14578                let old_range = selection.start..selection.end;
14579
14580                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14581                    // manually select word at selection
14582                    if ["string_content", "inline"].contains(&node.kind()) {
14583                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14584                        // ignore if word is already selected
14585                        if !word_range.is_empty() && old_range != word_range {
14586                            let (last_word_range, _) =
14587                                buffer.surrounding_word(old_range.end, false);
14588                            // only select word if start and end point belongs to same word
14589                            if word_range == last_word_range {
14590                                selected_larger_node = true;
14591                                return Selection {
14592                                    id: selection.id,
14593                                    start: word_range.start,
14594                                    end: word_range.end,
14595                                    goal: SelectionGoal::None,
14596                                    reversed: selection.reversed,
14597                                };
14598                            }
14599                        }
14600                    }
14601                }
14602
14603                let mut new_range = old_range.clone();
14604                while let Some((_node, containing_range)) =
14605                    buffer.syntax_ancestor(new_range.clone())
14606                {
14607                    new_range = match containing_range {
14608                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14609                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14610                    };
14611                    if !display_map.intersects_fold(new_range.start)
14612                        && !display_map.intersects_fold(new_range.end)
14613                    {
14614                        break;
14615                    }
14616                }
14617
14618                selected_larger_node |= new_range != old_range;
14619                Selection {
14620                    id: selection.id,
14621                    start: new_range.start,
14622                    end: new_range.end,
14623                    goal: SelectionGoal::None,
14624                    reversed: selection.reversed,
14625                }
14626            })
14627            .collect::<Vec<_>>();
14628
14629        if !selected_larger_node {
14630            return; // don't put this call in the history
14631        }
14632
14633        // scroll based on transformation done to the last selection created by the user
14634        let (last_old, last_new) = old_selections
14635            .last()
14636            .zip(new_selections.last().cloned())
14637            .expect("old_selections isn't empty");
14638
14639        // revert selection
14640        let is_selection_reversed = {
14641            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14642            new_selections.last_mut().expect("checked above").reversed =
14643                should_newest_selection_be_reversed;
14644            should_newest_selection_be_reversed
14645        };
14646
14647        if selected_larger_node {
14648            self.select_syntax_node_history.disable_clearing = true;
14649            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14650                s.select(new_selections.clone());
14651            });
14652            self.select_syntax_node_history.disable_clearing = false;
14653        }
14654
14655        let start_row = last_new.start.to_display_point(&display_map).row().0;
14656        let end_row = last_new.end.to_display_point(&display_map).row().0;
14657        let selection_height = end_row - start_row + 1;
14658        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14659
14660        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14661        let scroll_behavior = if fits_on_the_screen {
14662            self.request_autoscroll(Autoscroll::fit(), cx);
14663            SelectSyntaxNodeScrollBehavior::FitSelection
14664        } else if is_selection_reversed {
14665            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14666            SelectSyntaxNodeScrollBehavior::CursorTop
14667        } else {
14668            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14669            SelectSyntaxNodeScrollBehavior::CursorBottom
14670        };
14671
14672        self.select_syntax_node_history.push((
14673            old_selections,
14674            scroll_behavior,
14675            is_selection_reversed,
14676        ));
14677    }
14678
14679    pub fn select_smaller_syntax_node(
14680        &mut self,
14681        _: &SelectSmallerSyntaxNode,
14682        window: &mut Window,
14683        cx: &mut Context<Self>,
14684    ) {
14685        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14686
14687        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14688            self.select_syntax_node_history.pop()
14689        {
14690            if let Some(selection) = selections.last_mut() {
14691                selection.reversed = is_selection_reversed;
14692            }
14693
14694            self.select_syntax_node_history.disable_clearing = true;
14695            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14696                s.select(selections.to_vec());
14697            });
14698            self.select_syntax_node_history.disable_clearing = false;
14699
14700            match scroll_behavior {
14701                SelectSyntaxNodeScrollBehavior::CursorTop => {
14702                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14703                }
14704                SelectSyntaxNodeScrollBehavior::FitSelection => {
14705                    self.request_autoscroll(Autoscroll::fit(), cx);
14706                }
14707                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14708                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14709                }
14710            }
14711        }
14712    }
14713
14714    pub fn unwrap_syntax_node(
14715        &mut self,
14716        _: &UnwrapSyntaxNode,
14717        window: &mut Window,
14718        cx: &mut Context<Self>,
14719    ) {
14720        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14721
14722        let buffer = self.buffer.read(cx).snapshot(cx);
14723        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14724
14725        let edits = old_selections
14726            .iter()
14727            // only consider the first selection for now
14728            .take(1)
14729            .map(|selection| {
14730                // Only requires two branches once if-let-chains stabilize (#53667)
14731                let selection_range = if !selection.is_empty() {
14732                    selection.range()
14733                } else if let Some((_, ancestor_range)) =
14734                    buffer.syntax_ancestor(selection.start..selection.end)
14735                {
14736                    match ancestor_range {
14737                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14738                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14739                    }
14740                } else {
14741                    selection.range()
14742                };
14743
14744                let mut new_range = selection_range.clone();
14745                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(new_range.clone()) {
14746                    new_range = match ancestor_range {
14747                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14748                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14749                    };
14750                    if new_range.start < selection_range.start
14751                        || new_range.end > selection_range.end
14752                    {
14753                        break;
14754                    }
14755                }
14756
14757                (selection, selection_range, new_range)
14758            })
14759            .collect::<Vec<_>>();
14760
14761        self.transact(window, cx, |editor, window, cx| {
14762            for (_, child, parent) in &edits {
14763                let text = buffer.text_for_range(child.clone()).collect::<String>();
14764                editor.replace_text_in_range(Some(parent.clone()), &text, window, cx);
14765            }
14766
14767            editor.change_selections(
14768                SelectionEffects::scroll(Autoscroll::fit()),
14769                window,
14770                cx,
14771                |s| {
14772                    s.select(
14773                        edits
14774                            .iter()
14775                            .map(|(s, old, new)| Selection {
14776                                id: s.id,
14777                                start: new.start,
14778                                end: new.start + old.len(),
14779                                goal: SelectionGoal::None,
14780                                reversed: s.reversed,
14781                            })
14782                            .collect(),
14783                    );
14784                },
14785            );
14786        });
14787    }
14788
14789    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14790        if !EditorSettings::get_global(cx).gutter.runnables {
14791            self.clear_tasks();
14792            return Task::ready(());
14793        }
14794        let project = self.project.as_ref().map(Entity::downgrade);
14795        let task_sources = self.lsp_task_sources(cx);
14796        let multi_buffer = self.buffer.downgrade();
14797        cx.spawn_in(window, async move |editor, cx| {
14798            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14799            let Some(project) = project.and_then(|p| p.upgrade()) else {
14800                return;
14801            };
14802            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14803                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14804            }) else {
14805                return;
14806            };
14807
14808            let hide_runnables = project
14809                .update(cx, |project, cx| {
14810                    // Do not display any test indicators in non-dev server remote projects.
14811                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14812                })
14813                .unwrap_or(true);
14814            if hide_runnables {
14815                return;
14816            }
14817            let new_rows =
14818                cx.background_spawn({
14819                    let snapshot = display_snapshot.clone();
14820                    async move {
14821                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14822                    }
14823                })
14824                    .await;
14825            let Ok(lsp_tasks) =
14826                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14827            else {
14828                return;
14829            };
14830            let lsp_tasks = lsp_tasks.await;
14831
14832            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14833                lsp_tasks
14834                    .into_iter()
14835                    .flat_map(|(kind, tasks)| {
14836                        tasks.into_iter().filter_map(move |(location, task)| {
14837                            Some((kind.clone(), location?, task))
14838                        })
14839                    })
14840                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14841                        let buffer = location.target.buffer;
14842                        let buffer_snapshot = buffer.read(cx).snapshot();
14843                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14844                            |(excerpt_id, snapshot, _)| {
14845                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14846                                    display_snapshot
14847                                        .buffer_snapshot
14848                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14849                                } else {
14850                                    None
14851                                }
14852                            },
14853                        );
14854                        if let Some(offset) = offset {
14855                            let task_buffer_range =
14856                                location.target.range.to_point(&buffer_snapshot);
14857                            let context_buffer_range =
14858                                task_buffer_range.to_offset(&buffer_snapshot);
14859                            let context_range = BufferOffset(context_buffer_range.start)
14860                                ..BufferOffset(context_buffer_range.end);
14861
14862                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14863                                .or_insert_with(|| RunnableTasks {
14864                                    templates: Vec::new(),
14865                                    offset,
14866                                    column: task_buffer_range.start.column,
14867                                    extra_variables: HashMap::default(),
14868                                    context_range,
14869                                })
14870                                .templates
14871                                .push((kind, task.original_task().clone()));
14872                        }
14873
14874                        acc
14875                    })
14876            }) else {
14877                return;
14878            };
14879
14880            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14881                buffer.language_settings(cx).tasks.prefer_lsp
14882            }) else {
14883                return;
14884            };
14885
14886            let rows = Self::runnable_rows(
14887                project,
14888                display_snapshot,
14889                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14890                new_rows,
14891                cx.clone(),
14892            )
14893            .await;
14894            editor
14895                .update(cx, |editor, _| {
14896                    editor.clear_tasks();
14897                    for (key, mut value) in rows {
14898                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14899                            value.templates.extend(lsp_tasks.templates);
14900                        }
14901
14902                        editor.insert_tasks(key, value);
14903                    }
14904                    for (key, value) in lsp_tasks_by_rows {
14905                        editor.insert_tasks(key, value);
14906                    }
14907                })
14908                .ok();
14909        })
14910    }
14911    fn fetch_runnable_ranges(
14912        snapshot: &DisplaySnapshot,
14913        range: Range<Anchor>,
14914    ) -> Vec<language::RunnableRange> {
14915        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14916    }
14917
14918    fn runnable_rows(
14919        project: Entity<Project>,
14920        snapshot: DisplaySnapshot,
14921        prefer_lsp: bool,
14922        runnable_ranges: Vec<RunnableRange>,
14923        cx: AsyncWindowContext,
14924    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14925        cx.spawn(async move |cx| {
14926            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14927            for mut runnable in runnable_ranges {
14928                let Some(tasks) = cx
14929                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14930                    .ok()
14931                else {
14932                    continue;
14933                };
14934                let mut tasks = tasks.await;
14935
14936                if prefer_lsp {
14937                    tasks.retain(|(task_kind, _)| {
14938                        !matches!(task_kind, TaskSourceKind::Language { .. })
14939                    });
14940                }
14941                if tasks.is_empty() {
14942                    continue;
14943                }
14944
14945                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14946                let Some(row) = snapshot
14947                    .buffer_snapshot
14948                    .buffer_line_for_row(MultiBufferRow(point.row))
14949                    .map(|(_, range)| range.start.row)
14950                else {
14951                    continue;
14952                };
14953
14954                let context_range =
14955                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14956                runnable_rows.push((
14957                    (runnable.buffer_id, row),
14958                    RunnableTasks {
14959                        templates: tasks,
14960                        offset: snapshot
14961                            .buffer_snapshot
14962                            .anchor_before(runnable.run_range.start),
14963                        context_range,
14964                        column: point.column,
14965                        extra_variables: runnable.extra_captures,
14966                    },
14967                ));
14968            }
14969            runnable_rows
14970        })
14971    }
14972
14973    fn templates_with_tags(
14974        project: &Entity<Project>,
14975        runnable: &mut Runnable,
14976        cx: &mut App,
14977    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14978        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14979            let (worktree_id, file) = project
14980                .buffer_for_id(runnable.buffer, cx)
14981                .and_then(|buffer| buffer.read(cx).file())
14982                .map(|file| (file.worktree_id(cx), file.clone()))
14983                .unzip();
14984
14985            (
14986                project.task_store().read(cx).task_inventory().cloned(),
14987                worktree_id,
14988                file,
14989            )
14990        });
14991
14992        let tags = mem::take(&mut runnable.tags);
14993        let language = runnable.language.clone();
14994        cx.spawn(async move |cx| {
14995            let mut templates_with_tags = Vec::new();
14996            if let Some(inventory) = inventory {
14997                for RunnableTag(tag) in tags {
14998                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14999                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15000                    }) else {
15001                        return templates_with_tags;
15002                    };
15003                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15004                        move |(_, template)| {
15005                            template.tags.iter().any(|source_tag| source_tag == &tag)
15006                        },
15007                    ));
15008                }
15009            }
15010            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15011
15012            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15013                // Strongest source wins; if we have worktree tag binding, prefer that to
15014                // global and language bindings;
15015                // if we have a global binding, prefer that to language binding.
15016                let first_mismatch = templates_with_tags
15017                    .iter()
15018                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15019                if let Some(index) = first_mismatch {
15020                    templates_with_tags.truncate(index);
15021                }
15022            }
15023
15024            templates_with_tags
15025        })
15026    }
15027
15028    pub fn move_to_enclosing_bracket(
15029        &mut self,
15030        _: &MoveToEnclosingBracket,
15031        window: &mut Window,
15032        cx: &mut Context<Self>,
15033    ) {
15034        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15035        self.change_selections(Default::default(), window, cx, |s| {
15036            s.move_offsets_with(|snapshot, selection| {
15037                let Some(enclosing_bracket_ranges) =
15038                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15039                else {
15040                    return;
15041                };
15042
15043                let mut best_length = usize::MAX;
15044                let mut best_inside = false;
15045                let mut best_in_bracket_range = false;
15046                let mut best_destination = None;
15047                for (open, close) in enclosing_bracket_ranges {
15048                    let close = close.to_inclusive();
15049                    let length = close.end() - open.start;
15050                    let inside = selection.start >= open.end && selection.end <= *close.start();
15051                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15052                        || close.contains(&selection.head());
15053
15054                    // If best is next to a bracket and current isn't, skip
15055                    if !in_bracket_range && best_in_bracket_range {
15056                        continue;
15057                    }
15058
15059                    // Prefer smaller lengths unless best is inside and current isn't
15060                    if length > best_length && (best_inside || !inside) {
15061                        continue;
15062                    }
15063
15064                    best_length = length;
15065                    best_inside = inside;
15066                    best_in_bracket_range = in_bracket_range;
15067                    best_destination = Some(
15068                        if close.contains(&selection.start) && close.contains(&selection.end) {
15069                            if inside { open.end } else { open.start }
15070                        } else if inside {
15071                            *close.start()
15072                        } else {
15073                            *close.end()
15074                        },
15075                    );
15076                }
15077
15078                if let Some(destination) = best_destination {
15079                    selection.collapse_to(destination, SelectionGoal::None);
15080                }
15081            })
15082        });
15083    }
15084
15085    pub fn undo_selection(
15086        &mut self,
15087        _: &UndoSelection,
15088        window: &mut Window,
15089        cx: &mut Context<Self>,
15090    ) {
15091        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15092        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15093            self.selection_history.mode = SelectionHistoryMode::Undoing;
15094            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15095                this.end_selection(window, cx);
15096                this.change_selections(
15097                    SelectionEffects::scroll(Autoscroll::newest()),
15098                    window,
15099                    cx,
15100                    |s| s.select_anchors(entry.selections.to_vec()),
15101                );
15102            });
15103            self.selection_history.mode = SelectionHistoryMode::Normal;
15104
15105            self.select_next_state = entry.select_next_state;
15106            self.select_prev_state = entry.select_prev_state;
15107            self.add_selections_state = entry.add_selections_state;
15108        }
15109    }
15110
15111    pub fn redo_selection(
15112        &mut self,
15113        _: &RedoSelection,
15114        window: &mut Window,
15115        cx: &mut Context<Self>,
15116    ) {
15117        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15118        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15119            self.selection_history.mode = SelectionHistoryMode::Redoing;
15120            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15121                this.end_selection(window, cx);
15122                this.change_selections(
15123                    SelectionEffects::scroll(Autoscroll::newest()),
15124                    window,
15125                    cx,
15126                    |s| s.select_anchors(entry.selections.to_vec()),
15127                );
15128            });
15129            self.selection_history.mode = SelectionHistoryMode::Normal;
15130
15131            self.select_next_state = entry.select_next_state;
15132            self.select_prev_state = entry.select_prev_state;
15133            self.add_selections_state = entry.add_selections_state;
15134        }
15135    }
15136
15137    pub fn expand_excerpts(
15138        &mut self,
15139        action: &ExpandExcerpts,
15140        _: &mut Window,
15141        cx: &mut Context<Self>,
15142    ) {
15143        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15144    }
15145
15146    pub fn expand_excerpts_down(
15147        &mut self,
15148        action: &ExpandExcerptsDown,
15149        _: &mut Window,
15150        cx: &mut Context<Self>,
15151    ) {
15152        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15153    }
15154
15155    pub fn expand_excerpts_up(
15156        &mut self,
15157        action: &ExpandExcerptsUp,
15158        _: &mut Window,
15159        cx: &mut Context<Self>,
15160    ) {
15161        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15162    }
15163
15164    pub fn expand_excerpts_for_direction(
15165        &mut self,
15166        lines: u32,
15167        direction: ExpandExcerptDirection,
15168
15169        cx: &mut Context<Self>,
15170    ) {
15171        let selections = self.selections.disjoint_anchors();
15172
15173        let lines = if lines == 0 {
15174            EditorSettings::get_global(cx).expand_excerpt_lines
15175        } else {
15176            lines
15177        };
15178
15179        self.buffer.update(cx, |buffer, cx| {
15180            let snapshot = buffer.snapshot(cx);
15181            let mut excerpt_ids = selections
15182                .iter()
15183                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15184                .collect::<Vec<_>>();
15185            excerpt_ids.sort();
15186            excerpt_ids.dedup();
15187            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15188        })
15189    }
15190
15191    pub fn expand_excerpt(
15192        &mut self,
15193        excerpt: ExcerptId,
15194        direction: ExpandExcerptDirection,
15195        window: &mut Window,
15196        cx: &mut Context<Self>,
15197    ) {
15198        let current_scroll_position = self.scroll_position(cx);
15199        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15200        let mut should_scroll_up = false;
15201
15202        if direction == ExpandExcerptDirection::Down {
15203            let multi_buffer = self.buffer.read(cx);
15204            let snapshot = multi_buffer.snapshot(cx);
15205            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
15206                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
15207                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
15208                        let buffer_snapshot = buffer.read(cx).snapshot();
15209                        let excerpt_end_row =
15210                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15211                        let last_row = buffer_snapshot.max_point().row;
15212                        let lines_below = last_row.saturating_sub(excerpt_end_row);
15213                        should_scroll_up = lines_below >= lines_to_expand;
15214                    }
15215                }
15216            }
15217        }
15218
15219        self.buffer.update(cx, |buffer, cx| {
15220            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15221        });
15222
15223        if should_scroll_up {
15224            let new_scroll_position =
15225                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15226            self.set_scroll_position(new_scroll_position, window, cx);
15227        }
15228    }
15229
15230    pub fn go_to_singleton_buffer_point(
15231        &mut self,
15232        point: Point,
15233        window: &mut Window,
15234        cx: &mut Context<Self>,
15235    ) {
15236        self.go_to_singleton_buffer_range(point..point, window, cx);
15237    }
15238
15239    pub fn go_to_singleton_buffer_range(
15240        &mut self,
15241        range: Range<Point>,
15242        window: &mut Window,
15243        cx: &mut Context<Self>,
15244    ) {
15245        let multibuffer = self.buffer().read(cx);
15246        let Some(buffer) = multibuffer.as_singleton() else {
15247            return;
15248        };
15249        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15250            return;
15251        };
15252        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15253            return;
15254        };
15255        self.change_selections(
15256            SelectionEffects::default().nav_history(true),
15257            window,
15258            cx,
15259            |s| s.select_anchor_ranges([start..end]),
15260        );
15261    }
15262
15263    pub fn go_to_diagnostic(
15264        &mut self,
15265        action: &GoToDiagnostic,
15266        window: &mut Window,
15267        cx: &mut Context<Self>,
15268    ) {
15269        if !self.diagnostics_enabled() {
15270            return;
15271        }
15272        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15273        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15274    }
15275
15276    pub fn go_to_prev_diagnostic(
15277        &mut self,
15278        action: &GoToPreviousDiagnostic,
15279        window: &mut Window,
15280        cx: &mut Context<Self>,
15281    ) {
15282        if !self.diagnostics_enabled() {
15283            return;
15284        }
15285        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15286        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15287    }
15288
15289    pub fn go_to_diagnostic_impl(
15290        &mut self,
15291        direction: Direction,
15292        severity: GoToDiagnosticSeverityFilter,
15293        window: &mut Window,
15294        cx: &mut Context<Self>,
15295    ) {
15296        let buffer = self.buffer.read(cx).snapshot(cx);
15297        let selection = self.selections.newest::<usize>(cx);
15298
15299        let mut active_group_id = None;
15300        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
15301            if active_group.active_range.start.to_offset(&buffer) == selection.start {
15302                active_group_id = Some(active_group.group_id);
15303            }
15304        }
15305
15306        fn filtered(
15307            snapshot: EditorSnapshot,
15308            severity: GoToDiagnosticSeverityFilter,
15309            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15310        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15311            diagnostics
15312                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15313                .filter(|entry| entry.range.start != entry.range.end)
15314                .filter(|entry| !entry.diagnostic.is_unnecessary)
15315                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15316        }
15317
15318        let snapshot = self.snapshot(window, cx);
15319        let before = filtered(
15320            snapshot.clone(),
15321            severity,
15322            buffer
15323                .diagnostics_in_range(0..selection.start)
15324                .filter(|entry| entry.range.start <= selection.start),
15325        );
15326        let after = filtered(
15327            snapshot,
15328            severity,
15329            buffer
15330                .diagnostics_in_range(selection.start..buffer.len())
15331                .filter(|entry| entry.range.start >= selection.start),
15332        );
15333
15334        let mut found: Option<DiagnosticEntry<usize>> = None;
15335        if direction == Direction::Prev {
15336            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15337            {
15338                for diagnostic in prev_diagnostics.into_iter().rev() {
15339                    if diagnostic.range.start != selection.start
15340                        || active_group_id
15341                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15342                    {
15343                        found = Some(diagnostic);
15344                        break 'outer;
15345                    }
15346                }
15347            }
15348        } else {
15349            for diagnostic in after.chain(before) {
15350                if diagnostic.range.start != selection.start
15351                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15352                {
15353                    found = Some(diagnostic);
15354                    break;
15355                }
15356            }
15357        }
15358        let Some(next_diagnostic) = found else {
15359            return;
15360        };
15361
15362        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
15363            return;
15364        };
15365        self.change_selections(Default::default(), window, cx, |s| {
15366            s.select_ranges(vec![
15367                next_diagnostic.range.start..next_diagnostic.range.start,
15368            ])
15369        });
15370        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15371        self.refresh_edit_prediction(false, true, window, cx);
15372    }
15373
15374    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15375        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15376        let snapshot = self.snapshot(window, cx);
15377        let selection = self.selections.newest::<Point>(cx);
15378        self.go_to_hunk_before_or_after_position(
15379            &snapshot,
15380            selection.head(),
15381            Direction::Next,
15382            window,
15383            cx,
15384        );
15385    }
15386
15387    pub fn go_to_hunk_before_or_after_position(
15388        &mut self,
15389        snapshot: &EditorSnapshot,
15390        position: Point,
15391        direction: Direction,
15392        window: &mut Window,
15393        cx: &mut Context<Editor>,
15394    ) {
15395        let row = if direction == Direction::Next {
15396            self.hunk_after_position(snapshot, position)
15397                .map(|hunk| hunk.row_range.start)
15398        } else {
15399            self.hunk_before_position(snapshot, position)
15400        };
15401
15402        if let Some(row) = row {
15403            let destination = Point::new(row.0, 0);
15404            let autoscroll = Autoscroll::center();
15405
15406            self.unfold_ranges(&[destination..destination], false, false, cx);
15407            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15408                s.select_ranges([destination..destination]);
15409            });
15410        }
15411    }
15412
15413    fn hunk_after_position(
15414        &mut self,
15415        snapshot: &EditorSnapshot,
15416        position: Point,
15417    ) -> Option<MultiBufferDiffHunk> {
15418        snapshot
15419            .buffer_snapshot
15420            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15421            .find(|hunk| hunk.row_range.start.0 > position.row)
15422            .or_else(|| {
15423                snapshot
15424                    .buffer_snapshot
15425                    .diff_hunks_in_range(Point::zero()..position)
15426                    .find(|hunk| hunk.row_range.end.0 < position.row)
15427            })
15428    }
15429
15430    fn go_to_prev_hunk(
15431        &mut self,
15432        _: &GoToPreviousHunk,
15433        window: &mut Window,
15434        cx: &mut Context<Self>,
15435    ) {
15436        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15437        let snapshot = self.snapshot(window, cx);
15438        let selection = self.selections.newest::<Point>(cx);
15439        self.go_to_hunk_before_or_after_position(
15440            &snapshot,
15441            selection.head(),
15442            Direction::Prev,
15443            window,
15444            cx,
15445        );
15446    }
15447
15448    fn hunk_before_position(
15449        &mut self,
15450        snapshot: &EditorSnapshot,
15451        position: Point,
15452    ) -> Option<MultiBufferRow> {
15453        snapshot
15454            .buffer_snapshot
15455            .diff_hunk_before(position)
15456            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15457    }
15458
15459    fn go_to_next_change(
15460        &mut self,
15461        _: &GoToNextChange,
15462        window: &mut Window,
15463        cx: &mut Context<Self>,
15464    ) {
15465        if let Some(selections) = self
15466            .change_list
15467            .next_change(1, Direction::Next)
15468            .map(|s| s.to_vec())
15469        {
15470            self.change_selections(Default::default(), window, cx, |s| {
15471                let map = s.display_map();
15472                s.select_display_ranges(selections.iter().map(|a| {
15473                    let point = a.to_display_point(&map);
15474                    point..point
15475                }))
15476            })
15477        }
15478    }
15479
15480    fn go_to_previous_change(
15481        &mut self,
15482        _: &GoToPreviousChange,
15483        window: &mut Window,
15484        cx: &mut Context<Self>,
15485    ) {
15486        if let Some(selections) = self
15487            .change_list
15488            .next_change(1, Direction::Prev)
15489            .map(|s| s.to_vec())
15490        {
15491            self.change_selections(Default::default(), window, cx, |s| {
15492                let map = s.display_map();
15493                s.select_display_ranges(selections.iter().map(|a| {
15494                    let point = a.to_display_point(&map);
15495                    point..point
15496                }))
15497            })
15498        }
15499    }
15500
15501    fn go_to_line<T: 'static>(
15502        &mut self,
15503        position: Anchor,
15504        highlight_color: Option<Hsla>,
15505        window: &mut Window,
15506        cx: &mut Context<Self>,
15507    ) {
15508        let snapshot = self.snapshot(window, cx).display_snapshot;
15509        let position = position.to_point(&snapshot.buffer_snapshot);
15510        let start = snapshot
15511            .buffer_snapshot
15512            .clip_point(Point::new(position.row, 0), Bias::Left);
15513        let end = start + Point::new(1, 0);
15514        let start = snapshot.buffer_snapshot.anchor_before(start);
15515        let end = snapshot.buffer_snapshot.anchor_before(end);
15516
15517        self.highlight_rows::<T>(
15518            start..end,
15519            highlight_color
15520                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15521            Default::default(),
15522            cx,
15523        );
15524
15525        if self.buffer.read(cx).is_singleton() {
15526            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15527        }
15528    }
15529
15530    pub fn go_to_definition(
15531        &mut self,
15532        _: &GoToDefinition,
15533        window: &mut Window,
15534        cx: &mut Context<Self>,
15535    ) -> Task<Result<Navigated>> {
15536        let definition =
15537            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15538        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15539        cx.spawn_in(window, async move |editor, cx| {
15540            if definition.await? == Navigated::Yes {
15541                return Ok(Navigated::Yes);
15542            }
15543            match fallback_strategy {
15544                GoToDefinitionFallback::None => Ok(Navigated::No),
15545                GoToDefinitionFallback::FindAllReferences => {
15546                    match editor.update_in(cx, |editor, window, cx| {
15547                        editor.find_all_references(&FindAllReferences, window, cx)
15548                    })? {
15549                        Some(references) => references.await,
15550                        None => Ok(Navigated::No),
15551                    }
15552                }
15553            }
15554        })
15555    }
15556
15557    pub fn go_to_declaration(
15558        &mut self,
15559        _: &GoToDeclaration,
15560        window: &mut Window,
15561        cx: &mut Context<Self>,
15562    ) -> Task<Result<Navigated>> {
15563        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15564    }
15565
15566    pub fn go_to_declaration_split(
15567        &mut self,
15568        _: &GoToDeclaration,
15569        window: &mut Window,
15570        cx: &mut Context<Self>,
15571    ) -> Task<Result<Navigated>> {
15572        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15573    }
15574
15575    pub fn go_to_implementation(
15576        &mut self,
15577        _: &GoToImplementation,
15578        window: &mut Window,
15579        cx: &mut Context<Self>,
15580    ) -> Task<Result<Navigated>> {
15581        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15582    }
15583
15584    pub fn go_to_implementation_split(
15585        &mut self,
15586        _: &GoToImplementationSplit,
15587        window: &mut Window,
15588        cx: &mut Context<Self>,
15589    ) -> Task<Result<Navigated>> {
15590        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15591    }
15592
15593    pub fn go_to_type_definition(
15594        &mut self,
15595        _: &GoToTypeDefinition,
15596        window: &mut Window,
15597        cx: &mut Context<Self>,
15598    ) -> Task<Result<Navigated>> {
15599        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15600    }
15601
15602    pub fn go_to_definition_split(
15603        &mut self,
15604        _: &GoToDefinitionSplit,
15605        window: &mut Window,
15606        cx: &mut Context<Self>,
15607    ) -> Task<Result<Navigated>> {
15608        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15609    }
15610
15611    pub fn go_to_type_definition_split(
15612        &mut self,
15613        _: &GoToTypeDefinitionSplit,
15614        window: &mut Window,
15615        cx: &mut Context<Self>,
15616    ) -> Task<Result<Navigated>> {
15617        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15618    }
15619
15620    fn go_to_definition_of_kind(
15621        &mut self,
15622        kind: GotoDefinitionKind,
15623        split: bool,
15624        window: &mut Window,
15625        cx: &mut Context<Self>,
15626    ) -> Task<Result<Navigated>> {
15627        let Some(provider) = self.semantics_provider.clone() else {
15628            return Task::ready(Ok(Navigated::No));
15629        };
15630        let head = self.selections.newest::<usize>(cx).head();
15631        let buffer = self.buffer.read(cx);
15632        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
15633            text_anchor
15634        } else {
15635            return Task::ready(Ok(Navigated::No));
15636        };
15637
15638        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15639            return Task::ready(Ok(Navigated::No));
15640        };
15641
15642        cx.spawn_in(window, async move |editor, cx| {
15643            let definitions = definitions.await?;
15644            let navigated = editor
15645                .update_in(cx, |editor, window, cx| {
15646                    editor.navigate_to_hover_links(
15647                        Some(kind),
15648                        definitions
15649                            .into_iter()
15650                            .filter(|location| {
15651                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15652                            })
15653                            .map(HoverLink::Text)
15654                            .collect::<Vec<_>>(),
15655                        split,
15656                        window,
15657                        cx,
15658                    )
15659                })?
15660                .await?;
15661            anyhow::Ok(navigated)
15662        })
15663    }
15664
15665    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15666        let selection = self.selections.newest_anchor();
15667        let head = selection.head();
15668        let tail = selection.tail();
15669
15670        let Some((buffer, start_position)) =
15671            self.buffer.read(cx).text_anchor_for_position(head, cx)
15672        else {
15673            return;
15674        };
15675
15676        let end_position = if head != tail {
15677            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15678                return;
15679            };
15680            Some(pos)
15681        } else {
15682            None
15683        };
15684
15685        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15686            let url = if let Some(end_pos) = end_position {
15687                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15688            } else {
15689                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15690            };
15691
15692            if let Some(url) = url {
15693                editor.update(cx, |_, cx| {
15694                    cx.open_url(&url);
15695                })
15696            } else {
15697                Ok(())
15698            }
15699        });
15700
15701        url_finder.detach();
15702    }
15703
15704    pub fn open_selected_filename(
15705        &mut self,
15706        _: &OpenSelectedFilename,
15707        window: &mut Window,
15708        cx: &mut Context<Self>,
15709    ) {
15710        let Some(workspace) = self.workspace() else {
15711            return;
15712        };
15713
15714        let position = self.selections.newest_anchor().head();
15715
15716        let Some((buffer, buffer_position)) =
15717            self.buffer.read(cx).text_anchor_for_position(position, cx)
15718        else {
15719            return;
15720        };
15721
15722        let project = self.project.clone();
15723
15724        cx.spawn_in(window, async move |_, cx| {
15725            let result = find_file(&buffer, project, buffer_position, cx).await;
15726
15727            if let Some((_, path)) = result {
15728                workspace
15729                    .update_in(cx, |workspace, window, cx| {
15730                        workspace.open_resolved_path(path, window, cx)
15731                    })?
15732                    .await?;
15733            }
15734            anyhow::Ok(())
15735        })
15736        .detach();
15737    }
15738
15739    pub(crate) fn navigate_to_hover_links(
15740        &mut self,
15741        kind: Option<GotoDefinitionKind>,
15742        mut definitions: Vec<HoverLink>,
15743        split: bool,
15744        window: &mut Window,
15745        cx: &mut Context<Editor>,
15746    ) -> Task<Result<Navigated>> {
15747        // If there is one definition, just open it directly
15748        if definitions.len() == 1 {
15749            let definition = definitions.pop().unwrap();
15750
15751            enum TargetTaskResult {
15752                Location(Option<Location>),
15753                AlreadyNavigated,
15754            }
15755
15756            let target_task = match definition {
15757                HoverLink::Text(link) => {
15758                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
15759                }
15760                HoverLink::InlayHint(lsp_location, server_id) => {
15761                    let computation =
15762                        self.compute_target_location(lsp_location, server_id, window, cx);
15763                    cx.background_spawn(async move {
15764                        let location = computation.await?;
15765                        Ok(TargetTaskResult::Location(location))
15766                    })
15767                }
15768                HoverLink::Url(url) => {
15769                    cx.open_url(&url);
15770                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15771                }
15772                HoverLink::File(path) => {
15773                    if let Some(workspace) = self.workspace() {
15774                        cx.spawn_in(window, async move |_, cx| {
15775                            workspace
15776                                .update_in(cx, |workspace, window, cx| {
15777                                    workspace.open_resolved_path(path, window, cx)
15778                                })?
15779                                .await
15780                                .map(|_| TargetTaskResult::AlreadyNavigated)
15781                        })
15782                    } else {
15783                        Task::ready(Ok(TargetTaskResult::Location(None)))
15784                    }
15785                }
15786            };
15787            cx.spawn_in(window, async move |editor, cx| {
15788                let target = match target_task.await.context("target resolution task")? {
15789                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15790                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15791                    TargetTaskResult::Location(Some(target)) => target,
15792                };
15793
15794                editor.update_in(cx, |editor, window, cx| {
15795                    let Some(workspace) = editor.workspace() else {
15796                        return Navigated::No;
15797                    };
15798                    let pane = workspace.read(cx).active_pane().clone();
15799
15800                    let range = target.range.to_point(target.buffer.read(cx));
15801                    let range = editor.range_for_match(&range);
15802                    let range = collapse_multiline_range(range);
15803
15804                    if !split
15805                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15806                    {
15807                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15808                    } else {
15809                        window.defer(cx, move |window, cx| {
15810                            let target_editor: Entity<Self> =
15811                                workspace.update(cx, |workspace, cx| {
15812                                    let pane = if split {
15813                                        workspace.adjacent_pane(window, cx)
15814                                    } else {
15815                                        workspace.active_pane().clone()
15816                                    };
15817
15818                                    workspace.open_project_item(
15819                                        pane,
15820                                        target.buffer.clone(),
15821                                        true,
15822                                        true,
15823                                        window,
15824                                        cx,
15825                                    )
15826                                });
15827                            target_editor.update(cx, |target_editor, cx| {
15828                                // When selecting a definition in a different buffer, disable the nav history
15829                                // to avoid creating a history entry at the previous cursor location.
15830                                pane.update(cx, |pane, _| pane.disable_history());
15831                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15832                                pane.update(cx, |pane, _| pane.enable_history());
15833                            });
15834                        });
15835                    }
15836                    Navigated::Yes
15837                })
15838            })
15839        } else if !definitions.is_empty() {
15840            cx.spawn_in(window, async move |editor, cx| {
15841                let (title, location_tasks, workspace) = editor
15842                    .update_in(cx, |editor, window, cx| {
15843                        let tab_kind = match kind {
15844                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15845                            _ => "Definitions",
15846                        };
15847                        let title = definitions
15848                            .iter()
15849                            .find_map(|definition| match definition {
15850                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15851                                    let buffer = origin.buffer.read(cx);
15852                                    format!(
15853                                        "{} for {}",
15854                                        tab_kind,
15855                                        buffer
15856                                            .text_for_range(origin.range.clone())
15857                                            .collect::<String>()
15858                                    )
15859                                }),
15860                                HoverLink::InlayHint(_, _) => None,
15861                                HoverLink::Url(_) => None,
15862                                HoverLink::File(_) => None,
15863                            })
15864                            .unwrap_or(tab_kind.to_string());
15865                        let location_tasks = definitions
15866                            .into_iter()
15867                            .map(|definition| match definition {
15868                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15869                                HoverLink::InlayHint(lsp_location, server_id) => editor
15870                                    .compute_target_location(lsp_location, server_id, window, cx),
15871                                HoverLink::Url(_) => Task::ready(Ok(None)),
15872                                HoverLink::File(_) => Task::ready(Ok(None)),
15873                            })
15874                            .collect::<Vec<_>>();
15875                        (title, location_tasks, editor.workspace().clone())
15876                    })
15877                    .context("location tasks preparation")?;
15878
15879                let locations: Vec<Location> = future::join_all(location_tasks)
15880                    .await
15881                    .into_iter()
15882                    .filter_map(|location| location.transpose())
15883                    .collect::<Result<_>>()
15884                    .context("location tasks")?;
15885
15886                if locations.is_empty() {
15887                    return Ok(Navigated::No);
15888                }
15889
15890                let Some(workspace) = workspace else {
15891                    return Ok(Navigated::No);
15892                };
15893
15894                let opened = workspace
15895                    .update_in(cx, |workspace, window, cx| {
15896                        Self::open_locations_in_multibuffer(
15897                            workspace,
15898                            locations,
15899                            title,
15900                            split,
15901                            MultibufferSelectionMode::First,
15902                            window,
15903                            cx,
15904                        )
15905                    })
15906                    .ok();
15907
15908                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15909            })
15910        } else {
15911            Task::ready(Ok(Navigated::No))
15912        }
15913    }
15914
15915    fn compute_target_location(
15916        &self,
15917        lsp_location: lsp::Location,
15918        server_id: LanguageServerId,
15919        window: &mut Window,
15920        cx: &mut Context<Self>,
15921    ) -> Task<anyhow::Result<Option<Location>>> {
15922        let Some(project) = self.project.clone() else {
15923            return Task::ready(Ok(None));
15924        };
15925
15926        cx.spawn_in(window, async move |editor, cx| {
15927            let location_task = editor.update(cx, |_, cx| {
15928                project.update(cx, |project, cx| {
15929                    let language_server_name = project
15930                        .language_server_statuses(cx)
15931                        .find(|(id, _)| server_id == *id)
15932                        .map(|(_, status)| status.name.clone());
15933                    language_server_name.map(|language_server_name| {
15934                        project.open_local_buffer_via_lsp(
15935                            lsp_location.uri.clone(),
15936                            server_id,
15937                            language_server_name,
15938                            cx,
15939                        )
15940                    })
15941                })
15942            })?;
15943            let location = match location_task {
15944                Some(task) => Some({
15945                    let target_buffer_handle = task.await.context("open local buffer")?;
15946                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15947                        let target_start = target_buffer
15948                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15949                        let target_end = target_buffer
15950                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15951                        target_buffer.anchor_after(target_start)
15952                            ..target_buffer.anchor_before(target_end)
15953                    })?;
15954                    Location {
15955                        buffer: target_buffer_handle,
15956                        range,
15957                    }
15958                }),
15959                None => None,
15960            };
15961            Ok(location)
15962        })
15963    }
15964
15965    pub fn find_all_references(
15966        &mut self,
15967        _: &FindAllReferences,
15968        window: &mut Window,
15969        cx: &mut Context<Self>,
15970    ) -> Option<Task<Result<Navigated>>> {
15971        let selection = self.selections.newest::<usize>(cx);
15972        let multi_buffer = self.buffer.read(cx);
15973        let head = selection.head();
15974
15975        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15976        let head_anchor = multi_buffer_snapshot.anchor_at(
15977            head,
15978            if head < selection.tail() {
15979                Bias::Right
15980            } else {
15981                Bias::Left
15982            },
15983        );
15984
15985        match self
15986            .find_all_references_task_sources
15987            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15988        {
15989            Ok(_) => {
15990                log::info!(
15991                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15992                );
15993                return None;
15994            }
15995            Err(i) => {
15996                self.find_all_references_task_sources.insert(i, head_anchor);
15997            }
15998        }
15999
16000        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16001        let workspace = self.workspace()?;
16002        let project = workspace.read(cx).project().clone();
16003        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16004        Some(cx.spawn_in(window, async move |editor, cx| {
16005            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16006                if let Ok(i) = editor
16007                    .find_all_references_task_sources
16008                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16009                {
16010                    editor.find_all_references_task_sources.remove(i);
16011                }
16012            });
16013
16014            let locations = references.await?;
16015            if locations.is_empty() {
16016                return anyhow::Ok(Navigated::No);
16017            }
16018
16019            workspace.update_in(cx, |workspace, window, cx| {
16020                let title = locations
16021                    .first()
16022                    .as_ref()
16023                    .map(|location| {
16024                        let buffer = location.buffer.read(cx);
16025                        format!(
16026                            "References to `{}`",
16027                            buffer
16028                                .text_for_range(location.range.clone())
16029                                .collect::<String>()
16030                        )
16031                    })
16032                    .unwrap();
16033                Self::open_locations_in_multibuffer(
16034                    workspace,
16035                    locations,
16036                    title,
16037                    false,
16038                    MultibufferSelectionMode::First,
16039                    window,
16040                    cx,
16041                );
16042                Navigated::Yes
16043            })
16044        }))
16045    }
16046
16047    /// Opens a multibuffer with the given project locations in it
16048    pub fn open_locations_in_multibuffer(
16049        workspace: &mut Workspace,
16050        mut locations: Vec<Location>,
16051        title: String,
16052        split: bool,
16053        multibuffer_selection_mode: MultibufferSelectionMode,
16054        window: &mut Window,
16055        cx: &mut Context<Workspace>,
16056    ) {
16057        if locations.is_empty() {
16058            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16059            return;
16060        }
16061
16062        // If there are multiple definitions, open them in a multibuffer
16063        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16064        let mut locations = locations.into_iter().peekable();
16065        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16066        let capability = workspace.project().read(cx).capability();
16067
16068        let excerpt_buffer = cx.new(|cx| {
16069            let mut multibuffer = MultiBuffer::new(capability);
16070            while let Some(location) = locations.next() {
16071                let buffer = location.buffer.read(cx);
16072                let mut ranges_for_buffer = Vec::new();
16073                let range = location.range.to_point(buffer);
16074                ranges_for_buffer.push(range.clone());
16075
16076                while let Some(next_location) = locations.peek() {
16077                    if next_location.buffer == location.buffer {
16078                        ranges_for_buffer.push(next_location.range.to_point(buffer));
16079                        locations.next();
16080                    } else {
16081                        break;
16082                    }
16083                }
16084
16085                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16086                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16087                    PathKey::for_buffer(&location.buffer, cx),
16088                    location.buffer.clone(),
16089                    ranges_for_buffer,
16090                    DEFAULT_MULTIBUFFER_CONTEXT,
16091                    cx,
16092                );
16093                ranges.extend(new_ranges)
16094            }
16095
16096            multibuffer.with_title(title)
16097        });
16098
16099        let editor = cx.new(|cx| {
16100            Editor::for_multibuffer(
16101                excerpt_buffer,
16102                Some(workspace.project().clone()),
16103                window,
16104                cx,
16105            )
16106        });
16107        editor.update(cx, |editor, cx| {
16108            match multibuffer_selection_mode {
16109                MultibufferSelectionMode::First => {
16110                    if let Some(first_range) = ranges.first() {
16111                        editor.change_selections(
16112                            SelectionEffects::no_scroll(),
16113                            window,
16114                            cx,
16115                            |selections| {
16116                                selections.clear_disjoint();
16117                                selections
16118                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16119                            },
16120                        );
16121                    }
16122                    editor.highlight_background::<Self>(
16123                        &ranges,
16124                        |theme| theme.colors().editor_highlighted_line_background,
16125                        cx,
16126                    );
16127                }
16128                MultibufferSelectionMode::All => {
16129                    editor.change_selections(
16130                        SelectionEffects::no_scroll(),
16131                        window,
16132                        cx,
16133                        |selections| {
16134                            selections.clear_disjoint();
16135                            selections.select_anchor_ranges(ranges);
16136                        },
16137                    );
16138                }
16139            }
16140            editor.register_buffers_with_language_servers(cx);
16141        });
16142
16143        let item = Box::new(editor);
16144        let item_id = item.item_id();
16145
16146        if split {
16147            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
16148        } else {
16149            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16150                let (preview_item_id, preview_item_idx) =
16151                    workspace.active_pane().read_with(cx, |pane, _| {
16152                        (pane.preview_item_id(), pane.preview_item_idx())
16153                    });
16154
16155                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
16156
16157                if let Some(preview_item_id) = preview_item_id {
16158                    workspace.active_pane().update(cx, |pane, cx| {
16159                        pane.remove_item(preview_item_id, false, false, window, cx);
16160                    });
16161                }
16162            } else {
16163                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
16164            }
16165        }
16166        workspace.active_pane().update(cx, |pane, cx| {
16167            pane.set_preview_item_id(Some(item_id), cx);
16168        });
16169    }
16170
16171    pub fn rename(
16172        &mut self,
16173        _: &Rename,
16174        window: &mut Window,
16175        cx: &mut Context<Self>,
16176    ) -> Option<Task<Result<()>>> {
16177        use language::ToOffset as _;
16178
16179        let provider = self.semantics_provider.clone()?;
16180        let selection = self.selections.newest_anchor().clone();
16181        let (cursor_buffer, cursor_buffer_position) = self
16182            .buffer
16183            .read(cx)
16184            .text_anchor_for_position(selection.head(), cx)?;
16185        let (tail_buffer, cursor_buffer_position_end) = self
16186            .buffer
16187            .read(cx)
16188            .text_anchor_for_position(selection.tail(), cx)?;
16189        if tail_buffer != cursor_buffer {
16190            return None;
16191        }
16192
16193        let snapshot = cursor_buffer.read(cx).snapshot();
16194        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16195        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16196        let prepare_rename = provider
16197            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16198            .unwrap_or_else(|| Task::ready(Ok(None)));
16199        drop(snapshot);
16200
16201        Some(cx.spawn_in(window, async move |this, cx| {
16202            let rename_range = if let Some(range) = prepare_rename.await? {
16203                Some(range)
16204            } else {
16205                this.update(cx, |this, cx| {
16206                    let buffer = this.buffer.read(cx).snapshot(cx);
16207                    let mut buffer_highlights = this
16208                        .document_highlights_for_position(selection.head(), &buffer)
16209                        .filter(|highlight| {
16210                            highlight.start.excerpt_id == selection.head().excerpt_id
16211                                && highlight.end.excerpt_id == selection.head().excerpt_id
16212                        });
16213                    buffer_highlights
16214                        .next()
16215                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16216                })?
16217            };
16218            if let Some(rename_range) = rename_range {
16219                this.update_in(cx, |this, window, cx| {
16220                    let snapshot = cursor_buffer.read(cx).snapshot();
16221                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16222                    let cursor_offset_in_rename_range =
16223                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16224                    let cursor_offset_in_rename_range_end =
16225                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16226
16227                    this.take_rename(false, window, cx);
16228                    let buffer = this.buffer.read(cx).read(cx);
16229                    let cursor_offset = selection.head().to_offset(&buffer);
16230                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16231                    let rename_end = rename_start + rename_buffer_range.len();
16232                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16233                    let mut old_highlight_id = None;
16234                    let old_name: Arc<str> = buffer
16235                        .chunks(rename_start..rename_end, true)
16236                        .map(|chunk| {
16237                            if old_highlight_id.is_none() {
16238                                old_highlight_id = chunk.syntax_highlight_id;
16239                            }
16240                            chunk.text
16241                        })
16242                        .collect::<String>()
16243                        .into();
16244
16245                    drop(buffer);
16246
16247                    // Position the selection in the rename editor so that it matches the current selection.
16248                    this.show_local_selections = false;
16249                    let rename_editor = cx.new(|cx| {
16250                        let mut editor = Editor::single_line(window, cx);
16251                        editor.buffer.update(cx, |buffer, cx| {
16252                            buffer.edit([(0..0, old_name.clone())], None, cx)
16253                        });
16254                        let rename_selection_range = match cursor_offset_in_rename_range
16255                            .cmp(&cursor_offset_in_rename_range_end)
16256                        {
16257                            Ordering::Equal => {
16258                                editor.select_all(&SelectAll, window, cx);
16259                                return editor;
16260                            }
16261                            Ordering::Less => {
16262                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16263                            }
16264                            Ordering::Greater => {
16265                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16266                            }
16267                        };
16268                        if rename_selection_range.end > old_name.len() {
16269                            editor.select_all(&SelectAll, window, cx);
16270                        } else {
16271                            editor.change_selections(Default::default(), window, cx, |s| {
16272                                s.select_ranges([rename_selection_range]);
16273                            });
16274                        }
16275                        editor
16276                    });
16277                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16278                        if e == &EditorEvent::Focused {
16279                            cx.emit(EditorEvent::FocusedIn)
16280                        }
16281                    })
16282                    .detach();
16283
16284                    let write_highlights =
16285                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16286                    let read_highlights =
16287                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16288                    let ranges = write_highlights
16289                        .iter()
16290                        .flat_map(|(_, ranges)| ranges.iter())
16291                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16292                        .cloned()
16293                        .collect();
16294
16295                    this.highlight_text::<Rename>(
16296                        ranges,
16297                        HighlightStyle {
16298                            fade_out: Some(0.6),
16299                            ..Default::default()
16300                        },
16301                        cx,
16302                    );
16303                    let rename_focus_handle = rename_editor.focus_handle(cx);
16304                    window.focus(&rename_focus_handle);
16305                    let block_id = this.insert_blocks(
16306                        [BlockProperties {
16307                            style: BlockStyle::Flex,
16308                            placement: BlockPlacement::Below(range.start),
16309                            height: Some(1),
16310                            render: Arc::new({
16311                                let rename_editor = rename_editor.clone();
16312                                move |cx: &mut BlockContext| {
16313                                    let mut text_style = cx.editor_style.text.clone();
16314                                    if let Some(highlight_style) = old_highlight_id
16315                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16316                                    {
16317                                        text_style = text_style.highlight(highlight_style);
16318                                    }
16319                                    div()
16320                                        .block_mouse_except_scroll()
16321                                        .pl(cx.anchor_x)
16322                                        .child(EditorElement::new(
16323                                            &rename_editor,
16324                                            EditorStyle {
16325                                                background: cx.theme().system().transparent,
16326                                                local_player: cx.editor_style.local_player,
16327                                                text: text_style,
16328                                                scrollbar_width: cx.editor_style.scrollbar_width,
16329                                                syntax: cx.editor_style.syntax.clone(),
16330                                                status: cx.editor_style.status.clone(),
16331                                                inlay_hints_style: HighlightStyle {
16332                                                    font_weight: Some(FontWeight::BOLD),
16333                                                    ..make_inlay_hints_style(cx.app)
16334                                                },
16335                                                edit_prediction_styles: make_suggestion_styles(
16336                                                    cx.app,
16337                                                ),
16338                                                ..EditorStyle::default()
16339                                            },
16340                                        ))
16341                                        .into_any_element()
16342                                }
16343                            }),
16344                            priority: 0,
16345                        }],
16346                        Some(Autoscroll::fit()),
16347                        cx,
16348                    )[0];
16349                    this.pending_rename = Some(RenameState {
16350                        range,
16351                        old_name,
16352                        editor: rename_editor,
16353                        block_id,
16354                    });
16355                })?;
16356            }
16357
16358            Ok(())
16359        }))
16360    }
16361
16362    pub fn confirm_rename(
16363        &mut self,
16364        _: &ConfirmRename,
16365        window: &mut Window,
16366        cx: &mut Context<Self>,
16367    ) -> Option<Task<Result<()>>> {
16368        let rename = self.take_rename(false, window, cx)?;
16369        let workspace = self.workspace()?.downgrade();
16370        let (buffer, start) = self
16371            .buffer
16372            .read(cx)
16373            .text_anchor_for_position(rename.range.start, cx)?;
16374        let (end_buffer, _) = self
16375            .buffer
16376            .read(cx)
16377            .text_anchor_for_position(rename.range.end, cx)?;
16378        if buffer != end_buffer {
16379            return None;
16380        }
16381
16382        let old_name = rename.old_name;
16383        let new_name = rename.editor.read(cx).text(cx);
16384
16385        let rename = self.semantics_provider.as_ref()?.perform_rename(
16386            &buffer,
16387            start,
16388            new_name.clone(),
16389            cx,
16390        )?;
16391
16392        Some(cx.spawn_in(window, async move |editor, cx| {
16393            let project_transaction = rename.await?;
16394            Self::open_project_transaction(
16395                &editor,
16396                workspace,
16397                project_transaction,
16398                format!("Rename: {}{}", old_name, new_name),
16399                cx,
16400            )
16401            .await?;
16402
16403            editor.update(cx, |editor, cx| {
16404                editor.refresh_document_highlights(cx);
16405            })?;
16406            Ok(())
16407        }))
16408    }
16409
16410    fn take_rename(
16411        &mut self,
16412        moving_cursor: bool,
16413        window: &mut Window,
16414        cx: &mut Context<Self>,
16415    ) -> Option<RenameState> {
16416        let rename = self.pending_rename.take()?;
16417        if rename.editor.focus_handle(cx).is_focused(window) {
16418            window.focus(&self.focus_handle);
16419        }
16420
16421        self.remove_blocks(
16422            [rename.block_id].into_iter().collect(),
16423            Some(Autoscroll::fit()),
16424            cx,
16425        );
16426        self.clear_highlights::<Rename>(cx);
16427        self.show_local_selections = true;
16428
16429        if moving_cursor {
16430            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16431                editor.selections.newest::<usize>(cx).head()
16432            });
16433
16434            // Update the selection to match the position of the selection inside
16435            // the rename editor.
16436            let snapshot = self.buffer.read(cx).read(cx);
16437            let rename_range = rename.range.to_offset(&snapshot);
16438            let cursor_in_editor = snapshot
16439                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16440                .min(rename_range.end);
16441            drop(snapshot);
16442
16443            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16444                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16445            });
16446        } else {
16447            self.refresh_document_highlights(cx);
16448        }
16449
16450        Some(rename)
16451    }
16452
16453    pub fn pending_rename(&self) -> Option<&RenameState> {
16454        self.pending_rename.as_ref()
16455    }
16456
16457    fn format(
16458        &mut self,
16459        _: &Format,
16460        window: &mut Window,
16461        cx: &mut Context<Self>,
16462    ) -> Option<Task<Result<()>>> {
16463        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16464
16465        let project = match &self.project {
16466            Some(project) => project.clone(),
16467            None => return None,
16468        };
16469
16470        Some(self.perform_format(
16471            project,
16472            FormatTrigger::Manual,
16473            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16474            window,
16475            cx,
16476        ))
16477    }
16478
16479    fn format_selections(
16480        &mut self,
16481        _: &FormatSelections,
16482        window: &mut Window,
16483        cx: &mut Context<Self>,
16484    ) -> Option<Task<Result<()>>> {
16485        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16486
16487        let project = match &self.project {
16488            Some(project) => project.clone(),
16489            None => return None,
16490        };
16491
16492        let ranges = self
16493            .selections
16494            .all_adjusted(cx)
16495            .into_iter()
16496            .map(|selection| selection.range())
16497            .collect_vec();
16498
16499        Some(self.perform_format(
16500            project,
16501            FormatTrigger::Manual,
16502            FormatTarget::Ranges(ranges),
16503            window,
16504            cx,
16505        ))
16506    }
16507
16508    fn perform_format(
16509        &mut self,
16510        project: Entity<Project>,
16511        trigger: FormatTrigger,
16512        target: FormatTarget,
16513        window: &mut Window,
16514        cx: &mut Context<Self>,
16515    ) -> Task<Result<()>> {
16516        let buffer = self.buffer.clone();
16517        let (buffers, target) = match target {
16518            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16519            FormatTarget::Ranges(selection_ranges) => {
16520                let multi_buffer = buffer.read(cx);
16521                let snapshot = multi_buffer.read(cx);
16522                let mut buffers = HashSet::default();
16523                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16524                    BTreeMap::new();
16525                for selection_range in selection_ranges {
16526                    for (buffer, buffer_range, _) in
16527                        snapshot.range_to_buffer_ranges(selection_range)
16528                    {
16529                        let buffer_id = buffer.remote_id();
16530                        let start = buffer.anchor_before(buffer_range.start);
16531                        let end = buffer.anchor_after(buffer_range.end);
16532                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16533                        buffer_id_to_ranges
16534                            .entry(buffer_id)
16535                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16536                            .or_insert_with(|| vec![start..end]);
16537                    }
16538                }
16539                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16540            }
16541        };
16542
16543        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16544        let selections_prev = transaction_id_prev
16545            .and_then(|transaction_id_prev| {
16546                // default to selections as they were after the last edit, if we have them,
16547                // instead of how they are now.
16548                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16549                // will take you back to where you made the last edit, instead of staying where you scrolled
16550                self.selection_history
16551                    .transaction(transaction_id_prev)
16552                    .map(|t| t.0.clone())
16553            })
16554            .unwrap_or_else(|| {
16555                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
16556                self.selections.disjoint_anchors()
16557            });
16558
16559        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16560        let format = project.update(cx, |project, cx| {
16561            project.format(buffers, target, true, trigger, cx)
16562        });
16563
16564        cx.spawn_in(window, async move |editor, cx| {
16565            let transaction = futures::select_biased! {
16566                transaction = format.log_err().fuse() => transaction,
16567                () = timeout => {
16568                    log::warn!("timed out waiting for formatting");
16569                    None
16570                }
16571            };
16572
16573            buffer
16574                .update(cx, |buffer, cx| {
16575                    if let Some(transaction) = transaction {
16576                        if !buffer.is_singleton() {
16577                            buffer.push_transaction(&transaction.0, cx);
16578                        }
16579                    }
16580                    cx.notify();
16581                })
16582                .ok();
16583
16584            if let Some(transaction_id_now) =
16585                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16586            {
16587                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16588                if has_new_transaction {
16589                    _ = editor.update(cx, |editor, _| {
16590                        editor
16591                            .selection_history
16592                            .insert_transaction(transaction_id_now, selections_prev);
16593                    });
16594                }
16595            }
16596
16597            Ok(())
16598        })
16599    }
16600
16601    fn organize_imports(
16602        &mut self,
16603        _: &OrganizeImports,
16604        window: &mut Window,
16605        cx: &mut Context<Self>,
16606    ) -> Option<Task<Result<()>>> {
16607        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16608        let project = match &self.project {
16609            Some(project) => project.clone(),
16610            None => return None,
16611        };
16612        Some(self.perform_code_action_kind(
16613            project,
16614            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16615            window,
16616            cx,
16617        ))
16618    }
16619
16620    fn perform_code_action_kind(
16621        &mut self,
16622        project: Entity<Project>,
16623        kind: CodeActionKind,
16624        window: &mut Window,
16625        cx: &mut Context<Self>,
16626    ) -> Task<Result<()>> {
16627        let buffer = self.buffer.clone();
16628        let buffers = buffer.read(cx).all_buffers();
16629        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16630        let apply_action = project.update(cx, |project, cx| {
16631            project.apply_code_action_kind(buffers, kind, true, cx)
16632        });
16633        cx.spawn_in(window, async move |_, cx| {
16634            let transaction = futures::select_biased! {
16635                () = timeout => {
16636                    log::warn!("timed out waiting for executing code action");
16637                    None
16638                }
16639                transaction = apply_action.log_err().fuse() => transaction,
16640            };
16641            buffer
16642                .update(cx, |buffer, cx| {
16643                    // check if we need this
16644                    if let Some(transaction) = transaction {
16645                        if !buffer.is_singleton() {
16646                            buffer.push_transaction(&transaction.0, cx);
16647                        }
16648                    }
16649                    cx.notify();
16650                })
16651                .ok();
16652            Ok(())
16653        })
16654    }
16655
16656    pub fn restart_language_server(
16657        &mut self,
16658        _: &RestartLanguageServer,
16659        _: &mut Window,
16660        cx: &mut Context<Self>,
16661    ) {
16662        if let Some(project) = self.project.clone() {
16663            self.buffer.update(cx, |multi_buffer, cx| {
16664                project.update(cx, |project, cx| {
16665                    project.restart_language_servers_for_buffers(
16666                        multi_buffer.all_buffers().into_iter().collect(),
16667                        HashSet::default(),
16668                        cx,
16669                    );
16670                });
16671            })
16672        }
16673    }
16674
16675    pub fn stop_language_server(
16676        &mut self,
16677        _: &StopLanguageServer,
16678        _: &mut Window,
16679        cx: &mut Context<Self>,
16680    ) {
16681        if let Some(project) = self.project.clone() {
16682            self.buffer.update(cx, |multi_buffer, cx| {
16683                project.update(cx, |project, cx| {
16684                    project.stop_language_servers_for_buffers(
16685                        multi_buffer.all_buffers().into_iter().collect(),
16686                        HashSet::default(),
16687                        cx,
16688                    );
16689                    cx.emit(project::Event::RefreshInlayHints);
16690                });
16691            });
16692        }
16693    }
16694
16695    fn cancel_language_server_work(
16696        workspace: &mut Workspace,
16697        _: &actions::CancelLanguageServerWork,
16698        _: &mut Window,
16699        cx: &mut Context<Workspace>,
16700    ) {
16701        let project = workspace.project();
16702        let buffers = workspace
16703            .active_item(cx)
16704            .and_then(|item| item.act_as::<Editor>(cx))
16705            .map_or(HashSet::default(), |editor| {
16706                editor.read(cx).buffer.read(cx).all_buffers()
16707            });
16708        project.update(cx, |project, cx| {
16709            project.cancel_language_server_work_for_buffers(buffers, cx);
16710        });
16711    }
16712
16713    fn show_character_palette(
16714        &mut self,
16715        _: &ShowCharacterPalette,
16716        window: &mut Window,
16717        _: &mut Context<Self>,
16718    ) {
16719        window.show_character_palette();
16720    }
16721
16722    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16723        if !self.diagnostics_enabled() {
16724            return;
16725        }
16726
16727        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16728            let buffer = self.buffer.read(cx).snapshot(cx);
16729            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16730            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16731            let is_valid = buffer
16732                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16733                .any(|entry| {
16734                    entry.diagnostic.is_primary
16735                        && !entry.range.is_empty()
16736                        && entry.range.start == primary_range_start
16737                        && entry.diagnostic.message == active_diagnostics.active_message
16738                });
16739
16740            if !is_valid {
16741                self.dismiss_diagnostics(cx);
16742            }
16743        }
16744    }
16745
16746    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16747        match &self.active_diagnostics {
16748            ActiveDiagnostic::Group(group) => Some(group),
16749            _ => None,
16750        }
16751    }
16752
16753    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16754        if !self.diagnostics_enabled() {
16755            return;
16756        }
16757        self.dismiss_diagnostics(cx);
16758        self.active_diagnostics = ActiveDiagnostic::All;
16759    }
16760
16761    fn activate_diagnostics(
16762        &mut self,
16763        buffer_id: BufferId,
16764        diagnostic: DiagnosticEntry<usize>,
16765        window: &mut Window,
16766        cx: &mut Context<Self>,
16767    ) {
16768        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16769            return;
16770        }
16771        self.dismiss_diagnostics(cx);
16772        let snapshot = self.snapshot(window, cx);
16773        let buffer = self.buffer.read(cx).snapshot(cx);
16774        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16775            return;
16776        };
16777
16778        let diagnostic_group = buffer
16779            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16780            .collect::<Vec<_>>();
16781
16782        let blocks =
16783            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16784
16785        let blocks = self.display_map.update(cx, |display_map, cx| {
16786            display_map.insert_blocks(blocks, cx).into_iter().collect()
16787        });
16788        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16789            active_range: buffer.anchor_before(diagnostic.range.start)
16790                ..buffer.anchor_after(diagnostic.range.end),
16791            active_message: diagnostic.diagnostic.message.clone(),
16792            group_id: diagnostic.diagnostic.group_id,
16793            blocks,
16794        });
16795        cx.notify();
16796    }
16797
16798    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16799        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16800            return;
16801        };
16802
16803        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16804        if let ActiveDiagnostic::Group(group) = prev {
16805            self.display_map.update(cx, |display_map, cx| {
16806                display_map.remove_blocks(group.blocks, cx);
16807            });
16808            cx.notify();
16809        }
16810    }
16811
16812    /// Disable inline diagnostics rendering for this editor.
16813    pub fn disable_inline_diagnostics(&mut self) {
16814        self.inline_diagnostics_enabled = false;
16815        self.inline_diagnostics_update = Task::ready(());
16816        self.inline_diagnostics.clear();
16817    }
16818
16819    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16820        self.diagnostics_enabled = false;
16821        self.dismiss_diagnostics(cx);
16822        self.inline_diagnostics_update = Task::ready(());
16823        self.inline_diagnostics.clear();
16824    }
16825
16826    pub fn diagnostics_enabled(&self) -> bool {
16827        self.diagnostics_enabled && self.mode.is_full()
16828    }
16829
16830    pub fn inline_diagnostics_enabled(&self) -> bool {
16831        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16832    }
16833
16834    pub fn show_inline_diagnostics(&self) -> bool {
16835        self.show_inline_diagnostics
16836    }
16837
16838    pub fn toggle_inline_diagnostics(
16839        &mut self,
16840        _: &ToggleInlineDiagnostics,
16841        window: &mut Window,
16842        cx: &mut Context<Editor>,
16843    ) {
16844        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16845        self.refresh_inline_diagnostics(false, window, cx);
16846    }
16847
16848    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16849        self.diagnostics_max_severity = severity;
16850        self.display_map.update(cx, |display_map, _| {
16851            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16852        });
16853    }
16854
16855    pub fn toggle_diagnostics(
16856        &mut self,
16857        _: &ToggleDiagnostics,
16858        window: &mut Window,
16859        cx: &mut Context<Editor>,
16860    ) {
16861        if !self.diagnostics_enabled() {
16862            return;
16863        }
16864
16865        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16866            EditorSettings::get_global(cx)
16867                .diagnostics_max_severity
16868                .filter(|severity| severity != &DiagnosticSeverity::Off)
16869                .unwrap_or(DiagnosticSeverity::Hint)
16870        } else {
16871            DiagnosticSeverity::Off
16872        };
16873        self.set_max_diagnostics_severity(new_severity, cx);
16874        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16875            self.active_diagnostics = ActiveDiagnostic::None;
16876            self.inline_diagnostics_update = Task::ready(());
16877            self.inline_diagnostics.clear();
16878        } else {
16879            self.refresh_inline_diagnostics(false, window, cx);
16880        }
16881
16882        cx.notify();
16883    }
16884
16885    pub fn toggle_minimap(
16886        &mut self,
16887        _: &ToggleMinimap,
16888        window: &mut Window,
16889        cx: &mut Context<Editor>,
16890    ) {
16891        if self.supports_minimap(cx) {
16892            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16893        }
16894    }
16895
16896    fn refresh_inline_diagnostics(
16897        &mut self,
16898        debounce: bool,
16899        window: &mut Window,
16900        cx: &mut Context<Self>,
16901    ) {
16902        let max_severity = ProjectSettings::get_global(cx)
16903            .diagnostics
16904            .inline
16905            .max_severity
16906            .unwrap_or(self.diagnostics_max_severity);
16907
16908        if !self.inline_diagnostics_enabled()
16909            || !self.show_inline_diagnostics
16910            || max_severity == DiagnosticSeverity::Off
16911        {
16912            self.inline_diagnostics_update = Task::ready(());
16913            self.inline_diagnostics.clear();
16914            return;
16915        }
16916
16917        let debounce_ms = ProjectSettings::get_global(cx)
16918            .diagnostics
16919            .inline
16920            .update_debounce_ms;
16921        let debounce = if debounce && debounce_ms > 0 {
16922            Some(Duration::from_millis(debounce_ms))
16923        } else {
16924            None
16925        };
16926        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16927            if let Some(debounce) = debounce {
16928                cx.background_executor().timer(debounce).await;
16929            }
16930            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16931                editor
16932                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16933                    .ok()
16934            }) else {
16935                return;
16936            };
16937
16938            let new_inline_diagnostics = cx
16939                .background_spawn(async move {
16940                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16941                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16942                        let message = diagnostic_entry
16943                            .diagnostic
16944                            .message
16945                            .split_once('\n')
16946                            .map(|(line, _)| line)
16947                            .map(SharedString::new)
16948                            .unwrap_or_else(|| {
16949                                SharedString::from(diagnostic_entry.diagnostic.message)
16950                            });
16951                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16952                        let (Ok(i) | Err(i)) = inline_diagnostics
16953                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16954                        inline_diagnostics.insert(
16955                            i,
16956                            (
16957                                start_anchor,
16958                                InlineDiagnostic {
16959                                    message,
16960                                    group_id: diagnostic_entry.diagnostic.group_id,
16961                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16962                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16963                                    severity: diagnostic_entry.diagnostic.severity,
16964                                },
16965                            ),
16966                        );
16967                    }
16968                    inline_diagnostics
16969                })
16970                .await;
16971
16972            editor
16973                .update(cx, |editor, cx| {
16974                    editor.inline_diagnostics = new_inline_diagnostics;
16975                    cx.notify();
16976                })
16977                .ok();
16978        });
16979    }
16980
16981    fn pull_diagnostics(
16982        &mut self,
16983        buffer_id: Option<BufferId>,
16984        window: &Window,
16985        cx: &mut Context<Self>,
16986    ) -> Option<()> {
16987        if !self.mode().is_full() {
16988            return None;
16989        }
16990        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16991            .diagnostics
16992            .lsp_pull_diagnostics;
16993        if !pull_diagnostics_settings.enabled {
16994            return None;
16995        }
16996        let project = self.project.as_ref()?.downgrade();
16997        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16998        let mut buffers = self.buffer.read(cx).all_buffers();
16999        if let Some(buffer_id) = buffer_id {
17000            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17001        }
17002
17003        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17004            cx.background_executor().timer(debounce).await;
17005
17006            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17007                buffers
17008                    .into_iter()
17009                    .filter_map(|buffer| {
17010                        project
17011                            .update(cx, |project, cx| {
17012                                project.lsp_store().update(cx, |lsp_store, cx| {
17013                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17014                                })
17015                            })
17016                            .ok()
17017                    })
17018                    .collect::<FuturesUnordered<_>>()
17019            }) else {
17020                return;
17021            };
17022
17023            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17024                match pull_task {
17025                    Ok(()) => {
17026                        if editor
17027                            .update_in(cx, |editor, window, cx| {
17028                                editor.update_diagnostics_state(window, cx);
17029                            })
17030                            .is_err()
17031                        {
17032                            return;
17033                        }
17034                    }
17035                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17036                }
17037            }
17038        });
17039
17040        Some(())
17041    }
17042
17043    pub fn set_selections_from_remote(
17044        &mut self,
17045        selections: Vec<Selection<Anchor>>,
17046        pending_selection: Option<Selection<Anchor>>,
17047        window: &mut Window,
17048        cx: &mut Context<Self>,
17049    ) {
17050        let old_cursor_position = self.selections.newest_anchor().head();
17051        self.selections.change_with(cx, |s| {
17052            s.select_anchors(selections);
17053            if let Some(pending_selection) = pending_selection {
17054                s.set_pending(pending_selection, SelectMode::Character);
17055            } else {
17056                s.clear_pending();
17057            }
17058        });
17059        self.selections_did_change(
17060            false,
17061            &old_cursor_position,
17062            SelectionEffects::default(),
17063            window,
17064            cx,
17065        );
17066    }
17067
17068    pub fn transact(
17069        &mut self,
17070        window: &mut Window,
17071        cx: &mut Context<Self>,
17072        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17073    ) -> Option<TransactionId> {
17074        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17075            this.start_transaction_at(Instant::now(), window, cx);
17076            update(this, window, cx);
17077            this.end_transaction_at(Instant::now(), cx)
17078        })
17079    }
17080
17081    pub fn start_transaction_at(
17082        &mut self,
17083        now: Instant,
17084        window: &mut Window,
17085        cx: &mut Context<Self>,
17086    ) -> Option<TransactionId> {
17087        self.end_selection(window, cx);
17088        if let Some(tx_id) = self
17089            .buffer
17090            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17091        {
17092            self.selection_history
17093                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17094            cx.emit(EditorEvent::TransactionBegun {
17095                transaction_id: tx_id,
17096            });
17097            Some(tx_id)
17098        } else {
17099            None
17100        }
17101    }
17102
17103    pub fn end_transaction_at(
17104        &mut self,
17105        now: Instant,
17106        cx: &mut Context<Self>,
17107    ) -> Option<TransactionId> {
17108        if let Some(transaction_id) = self
17109            .buffer
17110            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17111        {
17112            if let Some((_, end_selections)) =
17113                self.selection_history.transaction_mut(transaction_id)
17114            {
17115                *end_selections = Some(self.selections.disjoint_anchors());
17116            } else {
17117                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17118            }
17119
17120            cx.emit(EditorEvent::Edited { transaction_id });
17121            Some(transaction_id)
17122        } else {
17123            None
17124        }
17125    }
17126
17127    pub fn modify_transaction_selection_history(
17128        &mut self,
17129        transaction_id: TransactionId,
17130        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17131    ) -> bool {
17132        self.selection_history
17133            .transaction_mut(transaction_id)
17134            .map(modify)
17135            .is_some()
17136    }
17137
17138    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17139        if self.selection_mark_mode {
17140            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17141                s.move_with(|_, sel| {
17142                    sel.collapse_to(sel.head(), SelectionGoal::None);
17143                });
17144            })
17145        }
17146        self.selection_mark_mode = true;
17147        cx.notify();
17148    }
17149
17150    pub fn swap_selection_ends(
17151        &mut self,
17152        _: &actions::SwapSelectionEnds,
17153        window: &mut Window,
17154        cx: &mut Context<Self>,
17155    ) {
17156        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17157            s.move_with(|_, sel| {
17158                if sel.start != sel.end {
17159                    sel.reversed = !sel.reversed
17160                }
17161            });
17162        });
17163        self.request_autoscroll(Autoscroll::newest(), cx);
17164        cx.notify();
17165    }
17166
17167    pub fn toggle_focus(
17168        workspace: &mut Workspace,
17169        _: &actions::ToggleFocus,
17170        window: &mut Window,
17171        cx: &mut Context<Workspace>,
17172    ) {
17173        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17174            return;
17175        };
17176        workspace.activate_item(&item, true, true, window, cx);
17177    }
17178
17179    pub fn toggle_fold(
17180        &mut self,
17181        _: &actions::ToggleFold,
17182        window: &mut Window,
17183        cx: &mut Context<Self>,
17184    ) {
17185        if self.is_singleton(cx) {
17186            let selection = self.selections.newest::<Point>(cx);
17187
17188            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17189            let range = if selection.is_empty() {
17190                let point = selection.head().to_display_point(&display_map);
17191                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17192                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17193                    .to_point(&display_map);
17194                start..end
17195            } else {
17196                selection.range()
17197            };
17198            if display_map.folds_in_range(range).next().is_some() {
17199                self.unfold_lines(&Default::default(), window, cx)
17200            } else {
17201                self.fold(&Default::default(), window, cx)
17202            }
17203        } else {
17204            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17205            let buffer_ids: HashSet<_> = self
17206                .selections
17207                .disjoint_anchor_ranges()
17208                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17209                .collect();
17210
17211            let should_unfold = buffer_ids
17212                .iter()
17213                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17214
17215            for buffer_id in buffer_ids {
17216                if should_unfold {
17217                    self.unfold_buffer(buffer_id, cx);
17218                } else {
17219                    self.fold_buffer(buffer_id, cx);
17220                }
17221            }
17222        }
17223    }
17224
17225    pub fn toggle_fold_recursive(
17226        &mut self,
17227        _: &actions::ToggleFoldRecursive,
17228        window: &mut Window,
17229        cx: &mut Context<Self>,
17230    ) {
17231        let selection = self.selections.newest::<Point>(cx);
17232
17233        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17234        let range = if selection.is_empty() {
17235            let point = selection.head().to_display_point(&display_map);
17236            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17237            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17238                .to_point(&display_map);
17239            start..end
17240        } else {
17241            selection.range()
17242        };
17243        if display_map.folds_in_range(range).next().is_some() {
17244            self.unfold_recursive(&Default::default(), window, cx)
17245        } else {
17246            self.fold_recursive(&Default::default(), window, cx)
17247        }
17248    }
17249
17250    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17251        if self.is_singleton(cx) {
17252            let mut to_fold = Vec::new();
17253            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17254            let selections = self.selections.all_adjusted(cx);
17255
17256            for selection in selections {
17257                let range = selection.range().sorted();
17258                let buffer_start_row = range.start.row;
17259
17260                if range.start.row != range.end.row {
17261                    let mut found = false;
17262                    let mut row = range.start.row;
17263                    while row <= range.end.row {
17264                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17265                        {
17266                            found = true;
17267                            row = crease.range().end.row + 1;
17268                            to_fold.push(crease);
17269                        } else {
17270                            row += 1
17271                        }
17272                    }
17273                    if found {
17274                        continue;
17275                    }
17276                }
17277
17278                for row in (0..=range.start.row).rev() {
17279                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17280                        if crease.range().end.row >= buffer_start_row {
17281                            to_fold.push(crease);
17282                            if row <= range.start.row {
17283                                break;
17284                            }
17285                        }
17286                    }
17287                }
17288            }
17289
17290            self.fold_creases(to_fold, true, window, cx);
17291        } else {
17292            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17293            let buffer_ids = self
17294                .selections
17295                .disjoint_anchor_ranges()
17296                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17297                .collect::<HashSet<_>>();
17298            for buffer_id in buffer_ids {
17299                self.fold_buffer(buffer_id, cx);
17300            }
17301        }
17302    }
17303
17304    pub fn toggle_fold_all(
17305        &mut self,
17306        _: &actions::ToggleFoldAll,
17307        window: &mut Window,
17308        cx: &mut Context<Self>,
17309    ) {
17310        if self.buffer.read(cx).is_singleton() {
17311            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17312            let has_folds = display_map
17313                .folds_in_range(0..display_map.buffer_snapshot.len())
17314                .next()
17315                .is_some();
17316
17317            if has_folds {
17318                self.unfold_all(&actions::UnfoldAll, window, cx);
17319            } else {
17320                self.fold_all(&actions::FoldAll, window, cx);
17321            }
17322        } else {
17323            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17324            let should_unfold = buffer_ids
17325                .iter()
17326                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17327
17328            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17329                editor
17330                    .update_in(cx, |editor, _, cx| {
17331                        for buffer_id in buffer_ids {
17332                            if should_unfold {
17333                                editor.unfold_buffer(buffer_id, cx);
17334                            } else {
17335                                editor.fold_buffer(buffer_id, cx);
17336                            }
17337                        }
17338                    })
17339                    .ok();
17340            });
17341        }
17342    }
17343
17344    fn fold_at_level(
17345        &mut self,
17346        fold_at: &FoldAtLevel,
17347        window: &mut Window,
17348        cx: &mut Context<Self>,
17349    ) {
17350        if !self.buffer.read(cx).is_singleton() {
17351            return;
17352        }
17353
17354        let fold_at_level = fold_at.0;
17355        let snapshot = self.buffer.read(cx).snapshot(cx);
17356        let mut to_fold = Vec::new();
17357        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17358
17359        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17360            while start_row < end_row {
17361                match self
17362                    .snapshot(window, cx)
17363                    .crease_for_buffer_row(MultiBufferRow(start_row))
17364                {
17365                    Some(crease) => {
17366                        let nested_start_row = crease.range().start.row + 1;
17367                        let nested_end_row = crease.range().end.row;
17368
17369                        if current_level < fold_at_level {
17370                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17371                        } else if current_level == fold_at_level {
17372                            to_fold.push(crease);
17373                        }
17374
17375                        start_row = nested_end_row + 1;
17376                    }
17377                    None => start_row += 1,
17378                }
17379            }
17380        }
17381
17382        self.fold_creases(to_fold, true, window, cx);
17383    }
17384
17385    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17386        if self.buffer.read(cx).is_singleton() {
17387            let mut fold_ranges = Vec::new();
17388            let snapshot = self.buffer.read(cx).snapshot(cx);
17389
17390            for row in 0..snapshot.max_row().0 {
17391                if let Some(foldable_range) = self
17392                    .snapshot(window, cx)
17393                    .crease_for_buffer_row(MultiBufferRow(row))
17394                {
17395                    fold_ranges.push(foldable_range);
17396                }
17397            }
17398
17399            self.fold_creases(fold_ranges, true, window, cx);
17400        } else {
17401            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17402                editor
17403                    .update_in(cx, |editor, _, cx| {
17404                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17405                            editor.fold_buffer(buffer_id, cx);
17406                        }
17407                    })
17408                    .ok();
17409            });
17410        }
17411    }
17412
17413    pub fn fold_function_bodies(
17414        &mut self,
17415        _: &actions::FoldFunctionBodies,
17416        window: &mut Window,
17417        cx: &mut Context<Self>,
17418    ) {
17419        let snapshot = self.buffer.read(cx).snapshot(cx);
17420
17421        let ranges = snapshot
17422            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17423            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17424            .collect::<Vec<_>>();
17425
17426        let creases = ranges
17427            .into_iter()
17428            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17429            .collect();
17430
17431        self.fold_creases(creases, true, window, cx);
17432    }
17433
17434    pub fn fold_recursive(
17435        &mut self,
17436        _: &actions::FoldRecursive,
17437        window: &mut Window,
17438        cx: &mut Context<Self>,
17439    ) {
17440        let mut to_fold = Vec::new();
17441        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17442        let selections = self.selections.all_adjusted(cx);
17443
17444        for selection in selections {
17445            let range = selection.range().sorted();
17446            let buffer_start_row = range.start.row;
17447
17448            if range.start.row != range.end.row {
17449                let mut found = false;
17450                for row in range.start.row..=range.end.row {
17451                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17452                        found = true;
17453                        to_fold.push(crease);
17454                    }
17455                }
17456                if found {
17457                    continue;
17458                }
17459            }
17460
17461            for row in (0..=range.start.row).rev() {
17462                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17463                    if crease.range().end.row >= buffer_start_row {
17464                        to_fold.push(crease);
17465                    } else {
17466                        break;
17467                    }
17468                }
17469            }
17470        }
17471
17472        self.fold_creases(to_fold, true, window, cx);
17473    }
17474
17475    pub fn fold_at(
17476        &mut self,
17477        buffer_row: MultiBufferRow,
17478        window: &mut Window,
17479        cx: &mut Context<Self>,
17480    ) {
17481        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17482
17483        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17484            let autoscroll = self
17485                .selections
17486                .all::<Point>(cx)
17487                .iter()
17488                .any(|selection| crease.range().overlaps(&selection.range()));
17489
17490            self.fold_creases(vec![crease], autoscroll, window, cx);
17491        }
17492    }
17493
17494    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17495        if self.is_singleton(cx) {
17496            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17497            let buffer = &display_map.buffer_snapshot;
17498            let selections = self.selections.all::<Point>(cx);
17499            let ranges = selections
17500                .iter()
17501                .map(|s| {
17502                    let range = s.display_range(&display_map).sorted();
17503                    let mut start = range.start.to_point(&display_map);
17504                    let mut end = range.end.to_point(&display_map);
17505                    start.column = 0;
17506                    end.column = buffer.line_len(MultiBufferRow(end.row));
17507                    start..end
17508                })
17509                .collect::<Vec<_>>();
17510
17511            self.unfold_ranges(&ranges, true, true, cx);
17512        } else {
17513            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17514            let buffer_ids = self
17515                .selections
17516                .disjoint_anchor_ranges()
17517                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17518                .collect::<HashSet<_>>();
17519            for buffer_id in buffer_ids {
17520                self.unfold_buffer(buffer_id, cx);
17521            }
17522        }
17523    }
17524
17525    pub fn unfold_recursive(
17526        &mut self,
17527        _: &UnfoldRecursive,
17528        _window: &mut Window,
17529        cx: &mut Context<Self>,
17530    ) {
17531        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17532        let selections = self.selections.all::<Point>(cx);
17533        let ranges = selections
17534            .iter()
17535            .map(|s| {
17536                let mut range = s.display_range(&display_map).sorted();
17537                *range.start.column_mut() = 0;
17538                *range.end.column_mut() = display_map.line_len(range.end.row());
17539                let start = range.start.to_point(&display_map);
17540                let end = range.end.to_point(&display_map);
17541                start..end
17542            })
17543            .collect::<Vec<_>>();
17544
17545        self.unfold_ranges(&ranges, true, true, cx);
17546    }
17547
17548    pub fn unfold_at(
17549        &mut self,
17550        buffer_row: MultiBufferRow,
17551        _window: &mut Window,
17552        cx: &mut Context<Self>,
17553    ) {
17554        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17555
17556        let intersection_range = Point::new(buffer_row.0, 0)
17557            ..Point::new(
17558                buffer_row.0,
17559                display_map.buffer_snapshot.line_len(buffer_row),
17560            );
17561
17562        let autoscroll = self
17563            .selections
17564            .all::<Point>(cx)
17565            .iter()
17566            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17567
17568        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17569    }
17570
17571    pub fn unfold_all(
17572        &mut self,
17573        _: &actions::UnfoldAll,
17574        _window: &mut Window,
17575        cx: &mut Context<Self>,
17576    ) {
17577        if self.buffer.read(cx).is_singleton() {
17578            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17579            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17580        } else {
17581            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17582                editor
17583                    .update(cx, |editor, cx| {
17584                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17585                            editor.unfold_buffer(buffer_id, cx);
17586                        }
17587                    })
17588                    .ok();
17589            });
17590        }
17591    }
17592
17593    pub fn fold_selected_ranges(
17594        &mut self,
17595        _: &FoldSelectedRanges,
17596        window: &mut Window,
17597        cx: &mut Context<Self>,
17598    ) {
17599        let selections = self.selections.all_adjusted(cx);
17600        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17601        let ranges = selections
17602            .into_iter()
17603            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17604            .collect::<Vec<_>>();
17605        self.fold_creases(ranges, true, window, cx);
17606    }
17607
17608    pub fn fold_ranges<T: ToOffset + Clone>(
17609        &mut self,
17610        ranges: Vec<Range<T>>,
17611        auto_scroll: bool,
17612        window: &mut Window,
17613        cx: &mut Context<Self>,
17614    ) {
17615        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17616        let ranges = ranges
17617            .into_iter()
17618            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17619            .collect::<Vec<_>>();
17620        self.fold_creases(ranges, auto_scroll, window, cx);
17621    }
17622
17623    pub fn fold_creases<T: ToOffset + Clone>(
17624        &mut self,
17625        creases: Vec<Crease<T>>,
17626        auto_scroll: bool,
17627        _window: &mut Window,
17628        cx: &mut Context<Self>,
17629    ) {
17630        if creases.is_empty() {
17631            return;
17632        }
17633
17634        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17635
17636        if auto_scroll {
17637            self.request_autoscroll(Autoscroll::fit(), cx);
17638        }
17639
17640        cx.notify();
17641
17642        self.scrollbar_marker_state.dirty = true;
17643        self.folds_did_change(cx);
17644    }
17645
17646    /// Removes any folds whose ranges intersect any of the given ranges.
17647    pub fn unfold_ranges<T: ToOffset + Clone>(
17648        &mut self,
17649        ranges: &[Range<T>],
17650        inclusive: bool,
17651        auto_scroll: bool,
17652        cx: &mut Context<Self>,
17653    ) {
17654        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17655            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17656        });
17657        self.folds_did_change(cx);
17658    }
17659
17660    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17661        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17662            return;
17663        }
17664        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17665        self.display_map.update(cx, |display_map, cx| {
17666            display_map.fold_buffers([buffer_id], cx)
17667        });
17668        cx.emit(EditorEvent::BufferFoldToggled {
17669            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17670            folded: true,
17671        });
17672        cx.notify();
17673    }
17674
17675    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17676        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17677            return;
17678        }
17679        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17680        self.display_map.update(cx, |display_map, cx| {
17681            display_map.unfold_buffers([buffer_id], cx);
17682        });
17683        cx.emit(EditorEvent::BufferFoldToggled {
17684            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17685            folded: false,
17686        });
17687        cx.notify();
17688    }
17689
17690    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17691        self.display_map.read(cx).is_buffer_folded(buffer)
17692    }
17693
17694    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17695        self.display_map.read(cx).folded_buffers()
17696    }
17697
17698    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17699        self.display_map.update(cx, |display_map, cx| {
17700            display_map.disable_header_for_buffer(buffer_id, cx);
17701        });
17702        cx.notify();
17703    }
17704
17705    /// Removes any folds with the given ranges.
17706    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17707        &mut self,
17708        ranges: &[Range<T>],
17709        type_id: TypeId,
17710        auto_scroll: bool,
17711        cx: &mut Context<Self>,
17712    ) {
17713        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17714            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17715        });
17716        self.folds_did_change(cx);
17717    }
17718
17719    fn remove_folds_with<T: ToOffset + Clone>(
17720        &mut self,
17721        ranges: &[Range<T>],
17722        auto_scroll: bool,
17723        cx: &mut Context<Self>,
17724        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17725    ) {
17726        if ranges.is_empty() {
17727            return;
17728        }
17729
17730        let mut buffers_affected = HashSet::default();
17731        let multi_buffer = self.buffer().read(cx);
17732        for range in ranges {
17733            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17734                buffers_affected.insert(buffer.read(cx).remote_id());
17735            };
17736        }
17737
17738        self.display_map.update(cx, update);
17739
17740        if auto_scroll {
17741            self.request_autoscroll(Autoscroll::fit(), cx);
17742        }
17743
17744        cx.notify();
17745        self.scrollbar_marker_state.dirty = true;
17746        self.active_indent_guides_state.dirty = true;
17747    }
17748
17749    pub fn update_renderer_widths(
17750        &mut self,
17751        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17752        cx: &mut Context<Self>,
17753    ) -> bool {
17754        self.display_map
17755            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17756    }
17757
17758    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17759        self.display_map.read(cx).fold_placeholder.clone()
17760    }
17761
17762    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17763        self.buffer.update(cx, |buffer, cx| {
17764            buffer.set_all_diff_hunks_expanded(cx);
17765        });
17766    }
17767
17768    pub fn expand_all_diff_hunks(
17769        &mut self,
17770        _: &ExpandAllDiffHunks,
17771        _window: &mut Window,
17772        cx: &mut Context<Self>,
17773    ) {
17774        self.buffer.update(cx, |buffer, cx| {
17775            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17776        });
17777    }
17778
17779    pub fn toggle_selected_diff_hunks(
17780        &mut self,
17781        _: &ToggleSelectedDiffHunks,
17782        _window: &mut Window,
17783        cx: &mut Context<Self>,
17784    ) {
17785        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17786        self.toggle_diff_hunks_in_ranges(ranges, cx);
17787    }
17788
17789    pub fn diff_hunks_in_ranges<'a>(
17790        &'a self,
17791        ranges: &'a [Range<Anchor>],
17792        buffer: &'a MultiBufferSnapshot,
17793    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17794        ranges.iter().flat_map(move |range| {
17795            let end_excerpt_id = range.end.excerpt_id;
17796            let range = range.to_point(buffer);
17797            let mut peek_end = range.end;
17798            if range.end.row < buffer.max_row().0 {
17799                peek_end = Point::new(range.end.row + 1, 0);
17800            }
17801            buffer
17802                .diff_hunks_in_range(range.start..peek_end)
17803                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17804        })
17805    }
17806
17807    pub fn has_stageable_diff_hunks_in_ranges(
17808        &self,
17809        ranges: &[Range<Anchor>],
17810        snapshot: &MultiBufferSnapshot,
17811    ) -> bool {
17812        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17813        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17814    }
17815
17816    pub fn toggle_staged_selected_diff_hunks(
17817        &mut self,
17818        _: &::git::ToggleStaged,
17819        _: &mut Window,
17820        cx: &mut Context<Self>,
17821    ) {
17822        let snapshot = self.buffer.read(cx).snapshot(cx);
17823        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17824        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17825        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17826    }
17827
17828    pub fn set_render_diff_hunk_controls(
17829        &mut self,
17830        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17831        cx: &mut Context<Self>,
17832    ) {
17833        self.render_diff_hunk_controls = render_diff_hunk_controls;
17834        cx.notify();
17835    }
17836
17837    pub fn stage_and_next(
17838        &mut self,
17839        _: &::git::StageAndNext,
17840        window: &mut Window,
17841        cx: &mut Context<Self>,
17842    ) {
17843        self.do_stage_or_unstage_and_next(true, window, cx);
17844    }
17845
17846    pub fn unstage_and_next(
17847        &mut self,
17848        _: &::git::UnstageAndNext,
17849        window: &mut Window,
17850        cx: &mut Context<Self>,
17851    ) {
17852        self.do_stage_or_unstage_and_next(false, window, cx);
17853    }
17854
17855    pub fn stage_or_unstage_diff_hunks(
17856        &mut self,
17857        stage: bool,
17858        ranges: Vec<Range<Anchor>>,
17859        cx: &mut Context<Self>,
17860    ) {
17861        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17862        cx.spawn(async move |this, cx| {
17863            task.await?;
17864            this.update(cx, |this, cx| {
17865                let snapshot = this.buffer.read(cx).snapshot(cx);
17866                let chunk_by = this
17867                    .diff_hunks_in_ranges(&ranges, &snapshot)
17868                    .chunk_by(|hunk| hunk.buffer_id);
17869                for (buffer_id, hunks) in &chunk_by {
17870                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17871                }
17872            })
17873        })
17874        .detach_and_log_err(cx);
17875    }
17876
17877    fn save_buffers_for_ranges_if_needed(
17878        &mut self,
17879        ranges: &[Range<Anchor>],
17880        cx: &mut Context<Editor>,
17881    ) -> Task<Result<()>> {
17882        let multibuffer = self.buffer.read(cx);
17883        let snapshot = multibuffer.read(cx);
17884        let buffer_ids: HashSet<_> = ranges
17885            .iter()
17886            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17887            .collect();
17888        drop(snapshot);
17889
17890        let mut buffers = HashSet::default();
17891        for buffer_id in buffer_ids {
17892            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17893                let buffer = buffer_entity.read(cx);
17894                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17895                {
17896                    buffers.insert(buffer_entity);
17897                }
17898            }
17899        }
17900
17901        if let Some(project) = &self.project {
17902            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17903        } else {
17904            Task::ready(Ok(()))
17905        }
17906    }
17907
17908    fn do_stage_or_unstage_and_next(
17909        &mut self,
17910        stage: bool,
17911        window: &mut Window,
17912        cx: &mut Context<Self>,
17913    ) {
17914        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17915
17916        if ranges.iter().any(|range| range.start != range.end) {
17917            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17918            return;
17919        }
17920
17921        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17922        let snapshot = self.snapshot(window, cx);
17923        let position = self.selections.newest::<Point>(cx).head();
17924        let mut row = snapshot
17925            .buffer_snapshot
17926            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17927            .find(|hunk| hunk.row_range.start.0 > position.row)
17928            .map(|hunk| hunk.row_range.start);
17929
17930        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17931        // Outside of the project diff editor, wrap around to the beginning.
17932        if !all_diff_hunks_expanded {
17933            row = row.or_else(|| {
17934                snapshot
17935                    .buffer_snapshot
17936                    .diff_hunks_in_range(Point::zero()..position)
17937                    .find(|hunk| hunk.row_range.end.0 < position.row)
17938                    .map(|hunk| hunk.row_range.start)
17939            });
17940        }
17941
17942        if let Some(row) = row {
17943            let destination = Point::new(row.0, 0);
17944            let autoscroll = Autoscroll::center();
17945
17946            self.unfold_ranges(&[destination..destination], false, false, cx);
17947            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17948                s.select_ranges([destination..destination]);
17949            });
17950        }
17951    }
17952
17953    fn do_stage_or_unstage(
17954        &self,
17955        stage: bool,
17956        buffer_id: BufferId,
17957        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17958        cx: &mut App,
17959    ) -> Option<()> {
17960        let project = self.project.as_ref()?;
17961        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17962        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17963        let buffer_snapshot = buffer.read(cx).snapshot();
17964        let file_exists = buffer_snapshot
17965            .file()
17966            .is_some_and(|file| file.disk_state().exists());
17967        diff.update(cx, |diff, cx| {
17968            diff.stage_or_unstage_hunks(
17969                stage,
17970                &hunks
17971                    .map(|hunk| buffer_diff::DiffHunk {
17972                        buffer_range: hunk.buffer_range,
17973                        diff_base_byte_range: hunk.diff_base_byte_range,
17974                        secondary_status: hunk.secondary_status,
17975                        range: Point::zero()..Point::zero(), // unused
17976                    })
17977                    .collect::<Vec<_>>(),
17978                &buffer_snapshot,
17979                file_exists,
17980                cx,
17981            )
17982        });
17983        None
17984    }
17985
17986    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17987        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17988        self.buffer
17989            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17990    }
17991
17992    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17993        self.buffer.update(cx, |buffer, cx| {
17994            let ranges = vec![Anchor::min()..Anchor::max()];
17995            if !buffer.all_diff_hunks_expanded()
17996                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17997            {
17998                buffer.collapse_diff_hunks(ranges, cx);
17999                true
18000            } else {
18001                false
18002            }
18003        })
18004    }
18005
18006    fn toggle_diff_hunks_in_ranges(
18007        &mut self,
18008        ranges: Vec<Range<Anchor>>,
18009        cx: &mut Context<Editor>,
18010    ) {
18011        self.buffer.update(cx, |buffer, cx| {
18012            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18013            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18014        })
18015    }
18016
18017    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18018        self.buffer.update(cx, |buffer, cx| {
18019            let snapshot = buffer.snapshot(cx);
18020            let excerpt_id = range.end.excerpt_id;
18021            let point_range = range.to_point(&snapshot);
18022            let expand = !buffer.single_hunk_is_expanded(range, cx);
18023            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18024        })
18025    }
18026
18027    pub(crate) fn apply_all_diff_hunks(
18028        &mut self,
18029        _: &ApplyAllDiffHunks,
18030        window: &mut Window,
18031        cx: &mut Context<Self>,
18032    ) {
18033        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18034
18035        let buffers = self.buffer.read(cx).all_buffers();
18036        for branch_buffer in buffers {
18037            branch_buffer.update(cx, |branch_buffer, cx| {
18038                branch_buffer.merge_into_base(Vec::new(), cx);
18039            });
18040        }
18041
18042        if let Some(project) = self.project.clone() {
18043            self.save(
18044                SaveOptions {
18045                    format: true,
18046                    autosave: false,
18047                },
18048                project,
18049                window,
18050                cx,
18051            )
18052            .detach_and_log_err(cx);
18053        }
18054    }
18055
18056    pub(crate) fn apply_selected_diff_hunks(
18057        &mut self,
18058        _: &ApplyDiffHunk,
18059        window: &mut Window,
18060        cx: &mut Context<Self>,
18061    ) {
18062        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18063        let snapshot = self.snapshot(window, cx);
18064        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18065        let mut ranges_by_buffer = HashMap::default();
18066        self.transact(window, cx, |editor, _window, cx| {
18067            for hunk in hunks {
18068                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18069                    ranges_by_buffer
18070                        .entry(buffer.clone())
18071                        .or_insert_with(Vec::new)
18072                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18073                }
18074            }
18075
18076            for (buffer, ranges) in ranges_by_buffer {
18077                buffer.update(cx, |buffer, cx| {
18078                    buffer.merge_into_base(ranges, cx);
18079                });
18080            }
18081        });
18082
18083        if let Some(project) = self.project.clone() {
18084            self.save(
18085                SaveOptions {
18086                    format: true,
18087                    autosave: false,
18088                },
18089                project,
18090                window,
18091                cx,
18092            )
18093            .detach_and_log_err(cx);
18094        }
18095    }
18096
18097    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18098        if hovered != self.gutter_hovered {
18099            self.gutter_hovered = hovered;
18100            cx.notify();
18101        }
18102    }
18103
18104    pub fn insert_blocks(
18105        &mut self,
18106        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18107        autoscroll: Option<Autoscroll>,
18108        cx: &mut Context<Self>,
18109    ) -> Vec<CustomBlockId> {
18110        let blocks = self
18111            .display_map
18112            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18113        if let Some(autoscroll) = autoscroll {
18114            self.request_autoscroll(autoscroll, cx);
18115        }
18116        cx.notify();
18117        blocks
18118    }
18119
18120    pub fn resize_blocks(
18121        &mut self,
18122        heights: HashMap<CustomBlockId, u32>,
18123        autoscroll: Option<Autoscroll>,
18124        cx: &mut Context<Self>,
18125    ) {
18126        self.display_map
18127            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18128        if let Some(autoscroll) = autoscroll {
18129            self.request_autoscroll(autoscroll, cx);
18130        }
18131        cx.notify();
18132    }
18133
18134    pub fn replace_blocks(
18135        &mut self,
18136        renderers: HashMap<CustomBlockId, RenderBlock>,
18137        autoscroll: Option<Autoscroll>,
18138        cx: &mut Context<Self>,
18139    ) {
18140        self.display_map
18141            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18142        if let Some(autoscroll) = autoscroll {
18143            self.request_autoscroll(autoscroll, cx);
18144        }
18145        cx.notify();
18146    }
18147
18148    pub fn remove_blocks(
18149        &mut self,
18150        block_ids: HashSet<CustomBlockId>,
18151        autoscroll: Option<Autoscroll>,
18152        cx: &mut Context<Self>,
18153    ) {
18154        self.display_map.update(cx, |display_map, cx| {
18155            display_map.remove_blocks(block_ids, cx)
18156        });
18157        if let Some(autoscroll) = autoscroll {
18158            self.request_autoscroll(autoscroll, cx);
18159        }
18160        cx.notify();
18161    }
18162
18163    pub fn row_for_block(
18164        &self,
18165        block_id: CustomBlockId,
18166        cx: &mut Context<Self>,
18167    ) -> Option<DisplayRow> {
18168        self.display_map
18169            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18170    }
18171
18172    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18173        self.focused_block = Some(focused_block);
18174    }
18175
18176    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18177        self.focused_block.take()
18178    }
18179
18180    pub fn insert_creases(
18181        &mut self,
18182        creases: impl IntoIterator<Item = Crease<Anchor>>,
18183        cx: &mut Context<Self>,
18184    ) -> Vec<CreaseId> {
18185        self.display_map
18186            .update(cx, |map, cx| map.insert_creases(creases, cx))
18187    }
18188
18189    pub fn remove_creases(
18190        &mut self,
18191        ids: impl IntoIterator<Item = CreaseId>,
18192        cx: &mut Context<Self>,
18193    ) -> Vec<(CreaseId, Range<Anchor>)> {
18194        self.display_map
18195            .update(cx, |map, cx| map.remove_creases(ids, cx))
18196    }
18197
18198    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18199        self.display_map
18200            .update(cx, |map, cx| map.snapshot(cx))
18201            .longest_row()
18202    }
18203
18204    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18205        self.display_map
18206            .update(cx, |map, cx| map.snapshot(cx))
18207            .max_point()
18208    }
18209
18210    pub fn text(&self, cx: &App) -> String {
18211        self.buffer.read(cx).read(cx).text()
18212    }
18213
18214    pub fn is_empty(&self, cx: &App) -> bool {
18215        self.buffer.read(cx).read(cx).is_empty()
18216    }
18217
18218    pub fn text_option(&self, cx: &App) -> Option<String> {
18219        let text = self.text(cx);
18220        let text = text.trim();
18221
18222        if text.is_empty() {
18223            return None;
18224        }
18225
18226        Some(text.to_string())
18227    }
18228
18229    pub fn set_text(
18230        &mut self,
18231        text: impl Into<Arc<str>>,
18232        window: &mut Window,
18233        cx: &mut Context<Self>,
18234    ) {
18235        self.transact(window, cx, |this, _, cx| {
18236            this.buffer
18237                .read(cx)
18238                .as_singleton()
18239                .expect("you can only call set_text on editors for singleton buffers")
18240                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18241        });
18242    }
18243
18244    pub fn display_text(&self, cx: &mut App) -> String {
18245        self.display_map
18246            .update(cx, |map, cx| map.snapshot(cx))
18247            .text()
18248    }
18249
18250    fn create_minimap(
18251        &self,
18252        minimap_settings: MinimapSettings,
18253        window: &mut Window,
18254        cx: &mut Context<Self>,
18255    ) -> Option<Entity<Self>> {
18256        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18257            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18258    }
18259
18260    fn initialize_new_minimap(
18261        &self,
18262        minimap_settings: MinimapSettings,
18263        window: &mut Window,
18264        cx: &mut Context<Self>,
18265    ) -> Entity<Self> {
18266        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18267
18268        let mut minimap = Editor::new_internal(
18269            EditorMode::Minimap {
18270                parent: cx.weak_entity(),
18271            },
18272            self.buffer.clone(),
18273            None,
18274            Some(self.display_map.clone()),
18275            window,
18276            cx,
18277        );
18278        minimap.scroll_manager.clone_state(&self.scroll_manager);
18279        minimap.set_text_style_refinement(TextStyleRefinement {
18280            font_size: Some(MINIMAP_FONT_SIZE),
18281            font_weight: Some(MINIMAP_FONT_WEIGHT),
18282            ..Default::default()
18283        });
18284        minimap.update_minimap_configuration(minimap_settings, cx);
18285        cx.new(|_| minimap)
18286    }
18287
18288    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18289        let current_line_highlight = minimap_settings
18290            .current_line_highlight
18291            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18292        self.set_current_line_highlight(Some(current_line_highlight));
18293    }
18294
18295    pub fn minimap(&self) -> Option<&Entity<Self>> {
18296        self.minimap
18297            .as_ref()
18298            .filter(|_| self.minimap_visibility.visible())
18299    }
18300
18301    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18302        let mut wrap_guides = smallvec![];
18303
18304        if self.show_wrap_guides == Some(false) {
18305            return wrap_guides;
18306        }
18307
18308        let settings = self.buffer.read(cx).language_settings(cx);
18309        if settings.show_wrap_guides {
18310            match self.soft_wrap_mode(cx) {
18311                SoftWrap::Column(soft_wrap) => {
18312                    wrap_guides.push((soft_wrap as usize, true));
18313                }
18314                SoftWrap::Bounded(soft_wrap) => {
18315                    wrap_guides.push((soft_wrap as usize, true));
18316                }
18317                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18318            }
18319            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18320        }
18321
18322        wrap_guides
18323    }
18324
18325    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18326        let settings = self.buffer.read(cx).language_settings(cx);
18327        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18328        match mode {
18329            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18330                SoftWrap::None
18331            }
18332            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18333            language_settings::SoftWrap::PreferredLineLength => {
18334                SoftWrap::Column(settings.preferred_line_length)
18335            }
18336            language_settings::SoftWrap::Bounded => {
18337                SoftWrap::Bounded(settings.preferred_line_length)
18338            }
18339        }
18340    }
18341
18342    pub fn set_soft_wrap_mode(
18343        &mut self,
18344        mode: language_settings::SoftWrap,
18345
18346        cx: &mut Context<Self>,
18347    ) {
18348        self.soft_wrap_mode_override = Some(mode);
18349        cx.notify();
18350    }
18351
18352    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18353        self.hard_wrap = hard_wrap;
18354        cx.notify();
18355    }
18356
18357    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18358        self.text_style_refinement = Some(style);
18359    }
18360
18361    /// called by the Element so we know what style we were most recently rendered with.
18362    pub(crate) fn set_style(
18363        &mut self,
18364        style: EditorStyle,
18365        window: &mut Window,
18366        cx: &mut Context<Self>,
18367    ) {
18368        // We intentionally do not inform the display map about the minimap style
18369        // so that wrapping is not recalculated and stays consistent for the editor
18370        // and its linked minimap.
18371        if !self.mode.is_minimap() {
18372            let rem_size = window.rem_size();
18373            self.display_map.update(cx, |map, cx| {
18374                map.set_font(
18375                    style.text.font(),
18376                    style.text.font_size.to_pixels(rem_size),
18377                    cx,
18378                )
18379            });
18380        }
18381        self.style = Some(style);
18382    }
18383
18384    pub fn style(&self) -> Option<&EditorStyle> {
18385        self.style.as_ref()
18386    }
18387
18388    // Called by the element. This method is not designed to be called outside of the editor
18389    // element's layout code because it does not notify when rewrapping is computed synchronously.
18390    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18391        self.display_map
18392            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18393    }
18394
18395    pub fn set_soft_wrap(&mut self) {
18396        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18397    }
18398
18399    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18400        if self.soft_wrap_mode_override.is_some() {
18401            self.soft_wrap_mode_override.take();
18402        } else {
18403            let soft_wrap = match self.soft_wrap_mode(cx) {
18404                SoftWrap::GitDiff => return,
18405                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18406                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18407                    language_settings::SoftWrap::None
18408                }
18409            };
18410            self.soft_wrap_mode_override = Some(soft_wrap);
18411        }
18412        cx.notify();
18413    }
18414
18415    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18416        let Some(workspace) = self.workspace() else {
18417            return;
18418        };
18419        let fs = workspace.read(cx).app_state().fs.clone();
18420        let current_show = TabBarSettings::get_global(cx).show;
18421        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18422            setting.show = Some(!current_show);
18423        });
18424    }
18425
18426    pub fn toggle_indent_guides(
18427        &mut self,
18428        _: &ToggleIndentGuides,
18429        _: &mut Window,
18430        cx: &mut Context<Self>,
18431    ) {
18432        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18433            self.buffer
18434                .read(cx)
18435                .language_settings(cx)
18436                .indent_guides
18437                .enabled
18438        });
18439        self.show_indent_guides = Some(!currently_enabled);
18440        cx.notify();
18441    }
18442
18443    fn should_show_indent_guides(&self) -> Option<bool> {
18444        self.show_indent_guides
18445    }
18446
18447    pub fn toggle_line_numbers(
18448        &mut self,
18449        _: &ToggleLineNumbers,
18450        _: &mut Window,
18451        cx: &mut Context<Self>,
18452    ) {
18453        let mut editor_settings = EditorSettings::get_global(cx).clone();
18454        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18455        EditorSettings::override_global(editor_settings, cx);
18456    }
18457
18458    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18459        if let Some(show_line_numbers) = self.show_line_numbers {
18460            return show_line_numbers;
18461        }
18462        EditorSettings::get_global(cx).gutter.line_numbers
18463    }
18464
18465    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18466        self.use_relative_line_numbers
18467            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18468    }
18469
18470    pub fn toggle_relative_line_numbers(
18471        &mut self,
18472        _: &ToggleRelativeLineNumbers,
18473        _: &mut Window,
18474        cx: &mut Context<Self>,
18475    ) {
18476        let is_relative = self.should_use_relative_line_numbers(cx);
18477        self.set_relative_line_number(Some(!is_relative), cx)
18478    }
18479
18480    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18481        self.use_relative_line_numbers = is_relative;
18482        cx.notify();
18483    }
18484
18485    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18486        self.show_gutter = show_gutter;
18487        cx.notify();
18488    }
18489
18490    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18491        self.show_scrollbars = ScrollbarAxes {
18492            horizontal: show,
18493            vertical: show,
18494        };
18495        cx.notify();
18496    }
18497
18498    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18499        self.show_scrollbars.vertical = show;
18500        cx.notify();
18501    }
18502
18503    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18504        self.show_scrollbars.horizontal = show;
18505        cx.notify();
18506    }
18507
18508    pub fn set_minimap_visibility(
18509        &mut self,
18510        minimap_visibility: MinimapVisibility,
18511        window: &mut Window,
18512        cx: &mut Context<Self>,
18513    ) {
18514        if self.minimap_visibility != minimap_visibility {
18515            if minimap_visibility.visible() && self.minimap.is_none() {
18516                let minimap_settings = EditorSettings::get_global(cx).minimap;
18517                self.minimap =
18518                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18519            }
18520            self.minimap_visibility = minimap_visibility;
18521            cx.notify();
18522        }
18523    }
18524
18525    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18526        self.set_show_scrollbars(false, cx);
18527        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18528    }
18529
18530    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18531        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18532    }
18533
18534    /// Normally the text in full mode and auto height editors is padded on the
18535    /// left side by roughly half a character width for improved hit testing.
18536    ///
18537    /// Use this method to disable this for cases where this is not wanted (e.g.
18538    /// if you want to align the editor text with some other text above or below)
18539    /// or if you want to add this padding to single-line editors.
18540    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18541        self.offset_content = offset_content;
18542        cx.notify();
18543    }
18544
18545    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18546        self.show_line_numbers = Some(show_line_numbers);
18547        cx.notify();
18548    }
18549
18550    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18551        self.disable_expand_excerpt_buttons = true;
18552        cx.notify();
18553    }
18554
18555    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18556        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18557        cx.notify();
18558    }
18559
18560    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18561        self.show_code_actions = Some(show_code_actions);
18562        cx.notify();
18563    }
18564
18565    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18566        self.show_runnables = Some(show_runnables);
18567        cx.notify();
18568    }
18569
18570    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18571        self.show_breakpoints = Some(show_breakpoints);
18572        cx.notify();
18573    }
18574
18575    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18576        if self.display_map.read(cx).masked != masked {
18577            self.display_map.update(cx, |map, _| map.masked = masked);
18578        }
18579        cx.notify()
18580    }
18581
18582    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18583        self.show_wrap_guides = Some(show_wrap_guides);
18584        cx.notify();
18585    }
18586
18587    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18588        self.show_indent_guides = Some(show_indent_guides);
18589        cx.notify();
18590    }
18591
18592    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18593        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18594            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
18595                if let Some(dir) = file.abs_path(cx).parent() {
18596                    return Some(dir.to_owned());
18597                }
18598            }
18599
18600            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18601                return Some(project_path.path.to_path_buf());
18602            }
18603        }
18604
18605        None
18606    }
18607
18608    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18609        self.active_excerpt(cx)?
18610            .1
18611            .read(cx)
18612            .file()
18613            .and_then(|f| f.as_local())
18614    }
18615
18616    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18617        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18618            let buffer = buffer.read(cx);
18619            if let Some(project_path) = buffer.project_path(cx) {
18620                let project = self.project.as_ref()?.read(cx);
18621                project.absolute_path(&project_path, cx)
18622            } else {
18623                buffer
18624                    .file()
18625                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18626            }
18627        })
18628    }
18629
18630    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18631        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18632            let project_path = buffer.read(cx).project_path(cx)?;
18633            let project = self.project.as_ref()?.read(cx);
18634            let entry = project.entry_for_path(&project_path, cx)?;
18635            let path = entry.path.to_path_buf();
18636            Some(path)
18637        })
18638    }
18639
18640    pub fn reveal_in_finder(
18641        &mut self,
18642        _: &RevealInFileManager,
18643        _window: &mut Window,
18644        cx: &mut Context<Self>,
18645    ) {
18646        if let Some(target) = self.target_file(cx) {
18647            cx.reveal_path(&target.abs_path(cx));
18648        }
18649    }
18650
18651    pub fn copy_path(
18652        &mut self,
18653        _: &zed_actions::workspace::CopyPath,
18654        _window: &mut Window,
18655        cx: &mut Context<Self>,
18656    ) {
18657        if let Some(path) = self.target_file_abs_path(cx) {
18658            if let Some(path) = path.to_str() {
18659                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18660            }
18661        }
18662    }
18663
18664    pub fn copy_relative_path(
18665        &mut self,
18666        _: &zed_actions::workspace::CopyRelativePath,
18667        _window: &mut Window,
18668        cx: &mut Context<Self>,
18669    ) {
18670        if let Some(path) = self.target_file_path(cx) {
18671            if let Some(path) = path.to_str() {
18672                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18673            }
18674        }
18675    }
18676
18677    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18678        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18679            buffer.read(cx).project_path(cx)
18680        } else {
18681            None
18682        }
18683    }
18684
18685    // Returns true if the editor handled a go-to-line request
18686    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18687        maybe!({
18688            let breakpoint_store = self.breakpoint_store.as_ref()?;
18689
18690            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18691            else {
18692                self.clear_row_highlights::<ActiveDebugLine>();
18693                return None;
18694            };
18695
18696            let position = active_stack_frame.position;
18697            let buffer_id = position.buffer_id?;
18698            let snapshot = self
18699                .project
18700                .as_ref()?
18701                .read(cx)
18702                .buffer_for_id(buffer_id, cx)?
18703                .read(cx)
18704                .snapshot();
18705
18706            let mut handled = false;
18707            for (id, ExcerptRange { context, .. }) in
18708                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18709            {
18710                if context.start.cmp(&position, &snapshot).is_ge()
18711                    || context.end.cmp(&position, &snapshot).is_lt()
18712                {
18713                    continue;
18714                }
18715                let snapshot = self.buffer.read(cx).snapshot(cx);
18716                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18717
18718                handled = true;
18719                self.clear_row_highlights::<ActiveDebugLine>();
18720
18721                self.go_to_line::<ActiveDebugLine>(
18722                    multibuffer_anchor,
18723                    Some(cx.theme().colors().editor_debugger_active_line_background),
18724                    window,
18725                    cx,
18726                );
18727
18728                cx.notify();
18729            }
18730
18731            handled.then_some(())
18732        })
18733        .is_some()
18734    }
18735
18736    pub fn copy_file_name_without_extension(
18737        &mut self,
18738        _: &CopyFileNameWithoutExtension,
18739        _: &mut Window,
18740        cx: &mut Context<Self>,
18741    ) {
18742        if let Some(file) = self.target_file(cx) {
18743            if let Some(file_stem) = file.path().file_stem() {
18744                if let Some(name) = file_stem.to_str() {
18745                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18746                }
18747            }
18748        }
18749    }
18750
18751    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18752        if let Some(file) = self.target_file(cx) {
18753            if let Some(file_name) = file.path().file_name() {
18754                if let Some(name) = file_name.to_str() {
18755                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18756                }
18757            }
18758        }
18759    }
18760
18761    pub fn toggle_git_blame(
18762        &mut self,
18763        _: &::git::Blame,
18764        window: &mut Window,
18765        cx: &mut Context<Self>,
18766    ) {
18767        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18768
18769        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18770            self.start_git_blame(true, window, cx);
18771        }
18772
18773        cx.notify();
18774    }
18775
18776    pub fn toggle_git_blame_inline(
18777        &mut self,
18778        _: &ToggleGitBlameInline,
18779        window: &mut Window,
18780        cx: &mut Context<Self>,
18781    ) {
18782        self.toggle_git_blame_inline_internal(true, window, cx);
18783        cx.notify();
18784    }
18785
18786    pub fn open_git_blame_commit(
18787        &mut self,
18788        _: &OpenGitBlameCommit,
18789        window: &mut Window,
18790        cx: &mut Context<Self>,
18791    ) {
18792        self.open_git_blame_commit_internal(window, cx);
18793    }
18794
18795    fn open_git_blame_commit_internal(
18796        &mut self,
18797        window: &mut Window,
18798        cx: &mut Context<Self>,
18799    ) -> Option<()> {
18800        let blame = self.blame.as_ref()?;
18801        let snapshot = self.snapshot(window, cx);
18802        let cursor = self.selections.newest::<Point>(cx).head();
18803        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18804        let blame_entry = blame
18805            .update(cx, |blame, cx| {
18806                blame
18807                    .blame_for_rows(
18808                        &[RowInfo {
18809                            buffer_id: Some(buffer.remote_id()),
18810                            buffer_row: Some(point.row),
18811                            ..Default::default()
18812                        }],
18813                        cx,
18814                    )
18815                    .next()
18816            })
18817            .flatten()?;
18818        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18819        let repo = blame.read(cx).repository(cx)?;
18820        let workspace = self.workspace()?.downgrade();
18821        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18822        None
18823    }
18824
18825    pub fn git_blame_inline_enabled(&self) -> bool {
18826        self.git_blame_inline_enabled
18827    }
18828
18829    pub fn toggle_selection_menu(
18830        &mut self,
18831        _: &ToggleSelectionMenu,
18832        _: &mut Window,
18833        cx: &mut Context<Self>,
18834    ) {
18835        self.show_selection_menu = self
18836            .show_selection_menu
18837            .map(|show_selections_menu| !show_selections_menu)
18838            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18839
18840        cx.notify();
18841    }
18842
18843    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18844        self.show_selection_menu
18845            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18846    }
18847
18848    fn start_git_blame(
18849        &mut self,
18850        user_triggered: bool,
18851        window: &mut Window,
18852        cx: &mut Context<Self>,
18853    ) {
18854        if let Some(project) = self.project.as_ref() {
18855            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18856                return;
18857            };
18858
18859            if buffer.read(cx).file().is_none() {
18860                return;
18861            }
18862
18863            let focused = self.focus_handle(cx).contains_focused(window, cx);
18864
18865            let project = project.clone();
18866            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18867            self.blame_subscription =
18868                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18869            self.blame = Some(blame);
18870        }
18871    }
18872
18873    fn toggle_git_blame_inline_internal(
18874        &mut self,
18875        user_triggered: bool,
18876        window: &mut Window,
18877        cx: &mut Context<Self>,
18878    ) {
18879        if self.git_blame_inline_enabled {
18880            self.git_blame_inline_enabled = false;
18881            self.show_git_blame_inline = false;
18882            self.show_git_blame_inline_delay_task.take();
18883        } else {
18884            self.git_blame_inline_enabled = true;
18885            self.start_git_blame_inline(user_triggered, window, cx);
18886        }
18887
18888        cx.notify();
18889    }
18890
18891    fn start_git_blame_inline(
18892        &mut self,
18893        user_triggered: bool,
18894        window: &mut Window,
18895        cx: &mut Context<Self>,
18896    ) {
18897        self.start_git_blame(user_triggered, window, cx);
18898
18899        if ProjectSettings::get_global(cx)
18900            .git
18901            .inline_blame_delay()
18902            .is_some()
18903        {
18904            self.start_inline_blame_timer(window, cx);
18905        } else {
18906            self.show_git_blame_inline = true
18907        }
18908    }
18909
18910    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18911        self.blame.as_ref()
18912    }
18913
18914    pub fn show_git_blame_gutter(&self) -> bool {
18915        self.show_git_blame_gutter
18916    }
18917
18918    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18919        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18920    }
18921
18922    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18923        self.show_git_blame_inline
18924            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18925            && !self.newest_selection_head_on_empty_line(cx)
18926            && self.has_blame_entries(cx)
18927    }
18928
18929    fn has_blame_entries(&self, cx: &App) -> bool {
18930        self.blame()
18931            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18932    }
18933
18934    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18935        let cursor_anchor = self.selections.newest_anchor().head();
18936
18937        let snapshot = self.buffer.read(cx).snapshot(cx);
18938        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18939
18940        snapshot.line_len(buffer_row) == 0
18941    }
18942
18943    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18944        let buffer_and_selection = maybe!({
18945            let selection = self.selections.newest::<Point>(cx);
18946            let selection_range = selection.range();
18947
18948            let multi_buffer = self.buffer().read(cx);
18949            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18950            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18951
18952            let (buffer, range, _) = if selection.reversed {
18953                buffer_ranges.first()
18954            } else {
18955                buffer_ranges.last()
18956            }?;
18957
18958            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18959                ..text::ToPoint::to_point(&range.end, &buffer).row;
18960            Some((
18961                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18962                selection,
18963            ))
18964        });
18965
18966        let Some((buffer, selection)) = buffer_and_selection else {
18967            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18968        };
18969
18970        let Some(project) = self.project.as_ref() else {
18971            return Task::ready(Err(anyhow!("editor does not have project")));
18972        };
18973
18974        project.update(cx, |project, cx| {
18975            project.get_permalink_to_line(&buffer, selection, cx)
18976        })
18977    }
18978
18979    pub fn copy_permalink_to_line(
18980        &mut self,
18981        _: &CopyPermalinkToLine,
18982        window: &mut Window,
18983        cx: &mut Context<Self>,
18984    ) {
18985        let permalink_task = self.get_permalink_to_line(cx);
18986        let workspace = self.workspace();
18987
18988        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18989            Ok(permalink) => {
18990                cx.update(|_, cx| {
18991                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18992                })
18993                .ok();
18994            }
18995            Err(err) => {
18996                let message = format!("Failed to copy permalink: {err}");
18997
18998                anyhow::Result::<()>::Err(err).log_err();
18999
19000                if let Some(workspace) = workspace {
19001                    workspace
19002                        .update_in(cx, |workspace, _, cx| {
19003                            struct CopyPermalinkToLine;
19004
19005                            workspace.show_toast(
19006                                Toast::new(
19007                                    NotificationId::unique::<CopyPermalinkToLine>(),
19008                                    message,
19009                                ),
19010                                cx,
19011                            )
19012                        })
19013                        .ok();
19014                }
19015            }
19016        })
19017        .detach();
19018    }
19019
19020    pub fn copy_file_location(
19021        &mut self,
19022        _: &CopyFileLocation,
19023        _: &mut Window,
19024        cx: &mut Context<Self>,
19025    ) {
19026        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19027        if let Some(file) = self.target_file(cx) {
19028            if let Some(path) = file.path().to_str() {
19029                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19030            }
19031        }
19032    }
19033
19034    pub fn open_permalink_to_line(
19035        &mut self,
19036        _: &OpenPermalinkToLine,
19037        window: &mut Window,
19038        cx: &mut Context<Self>,
19039    ) {
19040        let permalink_task = self.get_permalink_to_line(cx);
19041        let workspace = self.workspace();
19042
19043        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19044            Ok(permalink) => {
19045                cx.update(|_, cx| {
19046                    cx.open_url(permalink.as_ref());
19047                })
19048                .ok();
19049            }
19050            Err(err) => {
19051                let message = format!("Failed to open permalink: {err}");
19052
19053                anyhow::Result::<()>::Err(err).log_err();
19054
19055                if let Some(workspace) = workspace {
19056                    workspace
19057                        .update(cx, |workspace, cx| {
19058                            struct OpenPermalinkToLine;
19059
19060                            workspace.show_toast(
19061                                Toast::new(
19062                                    NotificationId::unique::<OpenPermalinkToLine>(),
19063                                    message,
19064                                ),
19065                                cx,
19066                            )
19067                        })
19068                        .ok();
19069                }
19070            }
19071        })
19072        .detach();
19073    }
19074
19075    pub fn insert_uuid_v4(
19076        &mut self,
19077        _: &InsertUuidV4,
19078        window: &mut Window,
19079        cx: &mut Context<Self>,
19080    ) {
19081        self.insert_uuid(UuidVersion::V4, window, cx);
19082    }
19083
19084    pub fn insert_uuid_v7(
19085        &mut self,
19086        _: &InsertUuidV7,
19087        window: &mut Window,
19088        cx: &mut Context<Self>,
19089    ) {
19090        self.insert_uuid(UuidVersion::V7, window, cx);
19091    }
19092
19093    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19094        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19095        self.transact(window, cx, |this, window, cx| {
19096            let edits = this
19097                .selections
19098                .all::<Point>(cx)
19099                .into_iter()
19100                .map(|selection| {
19101                    let uuid = match version {
19102                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19103                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19104                    };
19105
19106                    (selection.range(), uuid.to_string())
19107                });
19108            this.edit(edits, cx);
19109            this.refresh_edit_prediction(true, false, window, cx);
19110        });
19111    }
19112
19113    pub fn open_selections_in_multibuffer(
19114        &mut self,
19115        _: &OpenSelectionsInMultibuffer,
19116        window: &mut Window,
19117        cx: &mut Context<Self>,
19118    ) {
19119        let multibuffer = self.buffer.read(cx);
19120
19121        let Some(buffer) = multibuffer.as_singleton() else {
19122            return;
19123        };
19124
19125        let Some(workspace) = self.workspace() else {
19126            return;
19127        };
19128
19129        let title = multibuffer.title(cx).to_string();
19130
19131        let locations = self
19132            .selections
19133            .all_anchors(cx)
19134            .into_iter()
19135            .map(|selection| Location {
19136                buffer: buffer.clone(),
19137                range: selection.start.text_anchor..selection.end.text_anchor,
19138            })
19139            .collect::<Vec<_>>();
19140
19141        cx.spawn_in(window, async move |_, cx| {
19142            workspace.update_in(cx, |workspace, window, cx| {
19143                Self::open_locations_in_multibuffer(
19144                    workspace,
19145                    locations,
19146                    format!("Selections for '{title}'"),
19147                    false,
19148                    MultibufferSelectionMode::All,
19149                    window,
19150                    cx,
19151                );
19152            })
19153        })
19154        .detach();
19155    }
19156
19157    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19158    /// last highlight added will be used.
19159    ///
19160    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19161    pub fn highlight_rows<T: 'static>(
19162        &mut self,
19163        range: Range<Anchor>,
19164        color: Hsla,
19165        options: RowHighlightOptions,
19166        cx: &mut Context<Self>,
19167    ) {
19168        let snapshot = self.buffer().read(cx).snapshot(cx);
19169        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19170        let ix = row_highlights.binary_search_by(|highlight| {
19171            Ordering::Equal
19172                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19173                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19174        });
19175
19176        if let Err(mut ix) = ix {
19177            let index = post_inc(&mut self.highlight_order);
19178
19179            // If this range intersects with the preceding highlight, then merge it with
19180            // the preceding highlight. Otherwise insert a new highlight.
19181            let mut merged = false;
19182            if ix > 0 {
19183                let prev_highlight = &mut row_highlights[ix - 1];
19184                if prev_highlight
19185                    .range
19186                    .end
19187                    .cmp(&range.start, &snapshot)
19188                    .is_ge()
19189                {
19190                    ix -= 1;
19191                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19192                        prev_highlight.range.end = range.end;
19193                    }
19194                    merged = true;
19195                    prev_highlight.index = index;
19196                    prev_highlight.color = color;
19197                    prev_highlight.options = options;
19198                }
19199            }
19200
19201            if !merged {
19202                row_highlights.insert(
19203                    ix,
19204                    RowHighlight {
19205                        range: range.clone(),
19206                        index,
19207                        color,
19208                        options,
19209                        type_id: TypeId::of::<T>(),
19210                    },
19211                );
19212            }
19213
19214            // If any of the following highlights intersect with this one, merge them.
19215            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19216                let highlight = &row_highlights[ix];
19217                if next_highlight
19218                    .range
19219                    .start
19220                    .cmp(&highlight.range.end, &snapshot)
19221                    .is_le()
19222                {
19223                    if next_highlight
19224                        .range
19225                        .end
19226                        .cmp(&highlight.range.end, &snapshot)
19227                        .is_gt()
19228                    {
19229                        row_highlights[ix].range.end = next_highlight.range.end;
19230                    }
19231                    row_highlights.remove(ix + 1);
19232                } else {
19233                    break;
19234                }
19235            }
19236        }
19237    }
19238
19239    /// Remove any highlighted row ranges of the given type that intersect the
19240    /// given ranges.
19241    pub fn remove_highlighted_rows<T: 'static>(
19242        &mut self,
19243        ranges_to_remove: Vec<Range<Anchor>>,
19244        cx: &mut Context<Self>,
19245    ) {
19246        let snapshot = self.buffer().read(cx).snapshot(cx);
19247        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19248        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19249        row_highlights.retain(|highlight| {
19250            while let Some(range_to_remove) = ranges_to_remove.peek() {
19251                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19252                    Ordering::Less | Ordering::Equal => {
19253                        ranges_to_remove.next();
19254                    }
19255                    Ordering::Greater => {
19256                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19257                            Ordering::Less | Ordering::Equal => {
19258                                return false;
19259                            }
19260                            Ordering::Greater => break,
19261                        }
19262                    }
19263                }
19264            }
19265
19266            true
19267        })
19268    }
19269
19270    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19271    pub fn clear_row_highlights<T: 'static>(&mut self) {
19272        self.highlighted_rows.remove(&TypeId::of::<T>());
19273    }
19274
19275    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19276    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19277        self.highlighted_rows
19278            .get(&TypeId::of::<T>())
19279            .map_or(&[] as &[_], |vec| vec.as_slice())
19280            .iter()
19281            .map(|highlight| (highlight.range.clone(), highlight.color))
19282    }
19283
19284    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19285    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19286    /// Allows to ignore certain kinds of highlights.
19287    pub fn highlighted_display_rows(
19288        &self,
19289        window: &mut Window,
19290        cx: &mut App,
19291    ) -> BTreeMap<DisplayRow, LineHighlight> {
19292        let snapshot = self.snapshot(window, cx);
19293        let mut used_highlight_orders = HashMap::default();
19294        self.highlighted_rows
19295            .iter()
19296            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19297            .fold(
19298                BTreeMap::<DisplayRow, LineHighlight>::new(),
19299                |mut unique_rows, highlight| {
19300                    let start = highlight.range.start.to_display_point(&snapshot);
19301                    let end = highlight.range.end.to_display_point(&snapshot);
19302                    let start_row = start.row().0;
19303                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19304                        && end.column() == 0
19305                    {
19306                        end.row().0.saturating_sub(1)
19307                    } else {
19308                        end.row().0
19309                    };
19310                    for row in start_row..=end_row {
19311                        let used_index =
19312                            used_highlight_orders.entry(row).or_insert(highlight.index);
19313                        if highlight.index >= *used_index {
19314                            *used_index = highlight.index;
19315                            unique_rows.insert(
19316                                DisplayRow(row),
19317                                LineHighlight {
19318                                    include_gutter: highlight.options.include_gutter,
19319                                    border: None,
19320                                    background: highlight.color.into(),
19321                                    type_id: Some(highlight.type_id),
19322                                },
19323                            );
19324                        }
19325                    }
19326                    unique_rows
19327                },
19328            )
19329    }
19330
19331    pub fn highlighted_display_row_for_autoscroll(
19332        &self,
19333        snapshot: &DisplaySnapshot,
19334    ) -> Option<DisplayRow> {
19335        self.highlighted_rows
19336            .values()
19337            .flat_map(|highlighted_rows| highlighted_rows.iter())
19338            .filter_map(|highlight| {
19339                if highlight.options.autoscroll {
19340                    Some(highlight.range.start.to_display_point(snapshot).row())
19341                } else {
19342                    None
19343                }
19344            })
19345            .min()
19346    }
19347
19348    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19349        self.highlight_background::<SearchWithinRange>(
19350            ranges,
19351            |colors| colors.colors().editor_document_highlight_read_background,
19352            cx,
19353        )
19354    }
19355
19356    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19357        self.breadcrumb_header = Some(new_header);
19358    }
19359
19360    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19361        self.clear_background_highlights::<SearchWithinRange>(cx);
19362    }
19363
19364    pub fn highlight_background<T: 'static>(
19365        &mut self,
19366        ranges: &[Range<Anchor>],
19367        color_fetcher: fn(&Theme) -> Hsla,
19368        cx: &mut Context<Self>,
19369    ) {
19370        self.background_highlights.insert(
19371            HighlightKey::Type(TypeId::of::<T>()),
19372            (color_fetcher, Arc::from(ranges)),
19373        );
19374        self.scrollbar_marker_state.dirty = true;
19375        cx.notify();
19376    }
19377
19378    pub fn highlight_background_key<T: 'static>(
19379        &mut self,
19380        key: usize,
19381        ranges: &[Range<Anchor>],
19382        color_fetcher: fn(&Theme) -> Hsla,
19383        cx: &mut Context<Self>,
19384    ) {
19385        self.background_highlights.insert(
19386            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19387            (color_fetcher, Arc::from(ranges)),
19388        );
19389        self.scrollbar_marker_state.dirty = true;
19390        cx.notify();
19391    }
19392
19393    pub fn clear_background_highlights<T: 'static>(
19394        &mut self,
19395        cx: &mut Context<Self>,
19396    ) -> Option<BackgroundHighlight> {
19397        let text_highlights = self
19398            .background_highlights
19399            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19400        if !text_highlights.1.is_empty() {
19401            self.scrollbar_marker_state.dirty = true;
19402            cx.notify();
19403        }
19404        Some(text_highlights)
19405    }
19406
19407    pub fn highlight_gutter<T: 'static>(
19408        &mut self,
19409        ranges: impl Into<Vec<Range<Anchor>>>,
19410        color_fetcher: fn(&App) -> Hsla,
19411        cx: &mut Context<Self>,
19412    ) {
19413        self.gutter_highlights
19414            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19415        cx.notify();
19416    }
19417
19418    pub fn clear_gutter_highlights<T: 'static>(
19419        &mut self,
19420        cx: &mut Context<Self>,
19421    ) -> Option<GutterHighlight> {
19422        cx.notify();
19423        self.gutter_highlights.remove(&TypeId::of::<T>())
19424    }
19425
19426    pub fn insert_gutter_highlight<T: 'static>(
19427        &mut self,
19428        range: Range<Anchor>,
19429        color_fetcher: fn(&App) -> Hsla,
19430        cx: &mut Context<Self>,
19431    ) {
19432        let snapshot = self.buffer().read(cx).snapshot(cx);
19433        let mut highlights = self
19434            .gutter_highlights
19435            .remove(&TypeId::of::<T>())
19436            .map(|(_, highlights)| highlights)
19437            .unwrap_or_default();
19438        let ix = highlights.binary_search_by(|highlight| {
19439            Ordering::Equal
19440                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19441                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19442        });
19443        if let Err(ix) = ix {
19444            highlights.insert(ix, range);
19445        }
19446        self.gutter_highlights
19447            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19448    }
19449
19450    pub fn remove_gutter_highlights<T: 'static>(
19451        &mut self,
19452        ranges_to_remove: Vec<Range<Anchor>>,
19453        cx: &mut Context<Self>,
19454    ) {
19455        let snapshot = self.buffer().read(cx).snapshot(cx);
19456        let Some((color_fetcher, mut gutter_highlights)) =
19457            self.gutter_highlights.remove(&TypeId::of::<T>())
19458        else {
19459            return;
19460        };
19461        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19462        gutter_highlights.retain(|highlight| {
19463            while let Some(range_to_remove) = ranges_to_remove.peek() {
19464                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19465                    Ordering::Less | Ordering::Equal => {
19466                        ranges_to_remove.next();
19467                    }
19468                    Ordering::Greater => {
19469                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19470                            Ordering::Less | Ordering::Equal => {
19471                                return false;
19472                            }
19473                            Ordering::Greater => break,
19474                        }
19475                    }
19476                }
19477            }
19478
19479            true
19480        });
19481        self.gutter_highlights
19482            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19483    }
19484
19485    #[cfg(feature = "test-support")]
19486    pub fn all_text_highlights(
19487        &self,
19488        window: &mut Window,
19489        cx: &mut Context<Self>,
19490    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19491        let snapshot = self.snapshot(window, cx);
19492        self.display_map.update(cx, |display_map, _| {
19493            display_map
19494                .all_text_highlights()
19495                .map(|highlight| {
19496                    let (style, ranges) = highlight.as_ref();
19497                    (
19498                        *style,
19499                        ranges
19500                            .iter()
19501                            .map(|range| range.clone().to_display_points(&snapshot))
19502                            .collect(),
19503                    )
19504                })
19505                .collect()
19506        })
19507    }
19508
19509    #[cfg(feature = "test-support")]
19510    pub fn all_text_background_highlights(
19511        &self,
19512        window: &mut Window,
19513        cx: &mut Context<Self>,
19514    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19515        let snapshot = self.snapshot(window, cx);
19516        let buffer = &snapshot.buffer_snapshot;
19517        let start = buffer.anchor_before(0);
19518        let end = buffer.anchor_after(buffer.len());
19519        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19520    }
19521
19522    #[cfg(feature = "test-support")]
19523    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19524        let snapshot = self.buffer().read(cx).snapshot(cx);
19525
19526        let highlights = self
19527            .background_highlights
19528            .get(&HighlightKey::Type(TypeId::of::<
19529                items::BufferSearchHighlights,
19530            >()));
19531
19532        if let Some((_color, ranges)) = highlights {
19533            ranges
19534                .iter()
19535                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19536                .collect_vec()
19537        } else {
19538            vec![]
19539        }
19540    }
19541
19542    fn document_highlights_for_position<'a>(
19543        &'a self,
19544        position: Anchor,
19545        buffer: &'a MultiBufferSnapshot,
19546    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19547        let read_highlights = self
19548            .background_highlights
19549            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19550            .map(|h| &h.1);
19551        let write_highlights = self
19552            .background_highlights
19553            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19554            .map(|h| &h.1);
19555        let left_position = position.bias_left(buffer);
19556        let right_position = position.bias_right(buffer);
19557        read_highlights
19558            .into_iter()
19559            .chain(write_highlights)
19560            .flat_map(move |ranges| {
19561                let start_ix = match ranges.binary_search_by(|probe| {
19562                    let cmp = probe.end.cmp(&left_position, buffer);
19563                    if cmp.is_ge() {
19564                        Ordering::Greater
19565                    } else {
19566                        Ordering::Less
19567                    }
19568                }) {
19569                    Ok(i) | Err(i) => i,
19570                };
19571
19572                ranges[start_ix..]
19573                    .iter()
19574                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19575            })
19576    }
19577
19578    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19579        self.background_highlights
19580            .get(&HighlightKey::Type(TypeId::of::<T>()))
19581            .map_or(false, |(_, highlights)| !highlights.is_empty())
19582    }
19583
19584    pub fn background_highlights_in_range(
19585        &self,
19586        search_range: Range<Anchor>,
19587        display_snapshot: &DisplaySnapshot,
19588        theme: &Theme,
19589    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19590        let mut results = Vec::new();
19591        for (color_fetcher, ranges) in self.background_highlights.values() {
19592            let color = color_fetcher(theme);
19593            let start_ix = match ranges.binary_search_by(|probe| {
19594                let cmp = probe
19595                    .end
19596                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19597                if cmp.is_gt() {
19598                    Ordering::Greater
19599                } else {
19600                    Ordering::Less
19601                }
19602            }) {
19603                Ok(i) | Err(i) => i,
19604            };
19605            for range in &ranges[start_ix..] {
19606                if range
19607                    .start
19608                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19609                    .is_ge()
19610                {
19611                    break;
19612                }
19613
19614                let start = range.start.to_display_point(display_snapshot);
19615                let end = range.end.to_display_point(display_snapshot);
19616                results.push((start..end, color))
19617            }
19618        }
19619        results
19620    }
19621
19622    pub fn background_highlight_row_ranges<T: 'static>(
19623        &self,
19624        search_range: Range<Anchor>,
19625        display_snapshot: &DisplaySnapshot,
19626        count: usize,
19627    ) -> Vec<RangeInclusive<DisplayPoint>> {
19628        let mut results = Vec::new();
19629        let Some((_, ranges)) = self
19630            .background_highlights
19631            .get(&HighlightKey::Type(TypeId::of::<T>()))
19632        else {
19633            return vec![];
19634        };
19635
19636        let start_ix = match ranges.binary_search_by(|probe| {
19637            let cmp = probe
19638                .end
19639                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19640            if cmp.is_gt() {
19641                Ordering::Greater
19642            } else {
19643                Ordering::Less
19644            }
19645        }) {
19646            Ok(i) | Err(i) => i,
19647        };
19648        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19649            if let (Some(start_display), Some(end_display)) = (start, end) {
19650                results.push(
19651                    start_display.to_display_point(display_snapshot)
19652                        ..=end_display.to_display_point(display_snapshot),
19653                );
19654            }
19655        };
19656        let mut start_row: Option<Point> = None;
19657        let mut end_row: Option<Point> = None;
19658        if ranges.len() > count {
19659            return Vec::new();
19660        }
19661        for range in &ranges[start_ix..] {
19662            if range
19663                .start
19664                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19665                .is_ge()
19666            {
19667                break;
19668            }
19669            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19670            if let Some(current_row) = &end_row {
19671                if end.row == current_row.row {
19672                    continue;
19673                }
19674            }
19675            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19676            if start_row.is_none() {
19677                assert_eq!(end_row, None);
19678                start_row = Some(start);
19679                end_row = Some(end);
19680                continue;
19681            }
19682            if let Some(current_end) = end_row.as_mut() {
19683                if start.row > current_end.row + 1 {
19684                    push_region(start_row, end_row);
19685                    start_row = Some(start);
19686                    end_row = Some(end);
19687                } else {
19688                    // Merge two hunks.
19689                    *current_end = end;
19690                }
19691            } else {
19692                unreachable!();
19693            }
19694        }
19695        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19696        push_region(start_row, end_row);
19697        results
19698    }
19699
19700    pub fn gutter_highlights_in_range(
19701        &self,
19702        search_range: Range<Anchor>,
19703        display_snapshot: &DisplaySnapshot,
19704        cx: &App,
19705    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19706        let mut results = Vec::new();
19707        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19708            let color = color_fetcher(cx);
19709            let start_ix = match ranges.binary_search_by(|probe| {
19710                let cmp = probe
19711                    .end
19712                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19713                if cmp.is_gt() {
19714                    Ordering::Greater
19715                } else {
19716                    Ordering::Less
19717                }
19718            }) {
19719                Ok(i) | Err(i) => i,
19720            };
19721            for range in &ranges[start_ix..] {
19722                if range
19723                    .start
19724                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19725                    .is_ge()
19726                {
19727                    break;
19728                }
19729
19730                let start = range.start.to_display_point(display_snapshot);
19731                let end = range.end.to_display_point(display_snapshot);
19732                results.push((start..end, color))
19733            }
19734        }
19735        results
19736    }
19737
19738    /// Get the text ranges corresponding to the redaction query
19739    pub fn redacted_ranges(
19740        &self,
19741        search_range: Range<Anchor>,
19742        display_snapshot: &DisplaySnapshot,
19743        cx: &App,
19744    ) -> Vec<Range<DisplayPoint>> {
19745        display_snapshot
19746            .buffer_snapshot
19747            .redacted_ranges(search_range, |file| {
19748                if let Some(file) = file {
19749                    file.is_private()
19750                        && EditorSettings::get(
19751                            Some(SettingsLocation {
19752                                worktree_id: file.worktree_id(cx),
19753                                path: file.path().as_ref(),
19754                            }),
19755                            cx,
19756                        )
19757                        .redact_private_values
19758                } else {
19759                    false
19760                }
19761            })
19762            .map(|range| {
19763                range.start.to_display_point(display_snapshot)
19764                    ..range.end.to_display_point(display_snapshot)
19765            })
19766            .collect()
19767    }
19768
19769    pub fn highlight_text_key<T: 'static>(
19770        &mut self,
19771        key: usize,
19772        ranges: Vec<Range<Anchor>>,
19773        style: HighlightStyle,
19774        cx: &mut Context<Self>,
19775    ) {
19776        self.display_map.update(cx, |map, _| {
19777            map.highlight_text(
19778                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19779                ranges,
19780                style,
19781            );
19782        });
19783        cx.notify();
19784    }
19785
19786    pub fn highlight_text<T: 'static>(
19787        &mut self,
19788        ranges: Vec<Range<Anchor>>,
19789        style: HighlightStyle,
19790        cx: &mut Context<Self>,
19791    ) {
19792        self.display_map.update(cx, |map, _| {
19793            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19794        });
19795        cx.notify();
19796    }
19797
19798    pub(crate) fn highlight_inlays<T: 'static>(
19799        &mut self,
19800        highlights: Vec<InlayHighlight>,
19801        style: HighlightStyle,
19802        cx: &mut Context<Self>,
19803    ) {
19804        self.display_map.update(cx, |map, _| {
19805            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19806        });
19807        cx.notify();
19808    }
19809
19810    pub fn text_highlights<'a, T: 'static>(
19811        &'a self,
19812        cx: &'a App,
19813    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19814        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19815    }
19816
19817    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19818        let cleared = self
19819            .display_map
19820            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19821        if cleared {
19822            cx.notify();
19823        }
19824    }
19825
19826    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19827        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19828            && self.focus_handle.is_focused(window)
19829    }
19830
19831    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19832        self.show_cursor_when_unfocused = is_enabled;
19833        cx.notify();
19834    }
19835
19836    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19837        cx.notify();
19838    }
19839
19840    fn on_debug_session_event(
19841        &mut self,
19842        _session: Entity<Session>,
19843        event: &SessionEvent,
19844        cx: &mut Context<Self>,
19845    ) {
19846        match event {
19847            SessionEvent::InvalidateInlineValue => {
19848                self.refresh_inline_values(cx);
19849            }
19850            _ => {}
19851        }
19852    }
19853
19854    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19855        let Some(project) = self.project.clone() else {
19856            return;
19857        };
19858
19859        if !self.inline_value_cache.enabled {
19860            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19861            self.splice_inlays(&inlays, Vec::new(), cx);
19862            return;
19863        }
19864
19865        let current_execution_position = self
19866            .highlighted_rows
19867            .get(&TypeId::of::<ActiveDebugLine>())
19868            .and_then(|lines| lines.last().map(|line| line.range.end));
19869
19870        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19871            let inline_values = editor
19872                .update(cx, |editor, cx| {
19873                    let Some(current_execution_position) = current_execution_position else {
19874                        return Some(Task::ready(Ok(Vec::new())));
19875                    };
19876
19877                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19878                        let snapshot = buffer.snapshot(cx);
19879
19880                        let excerpt = snapshot.excerpt_containing(
19881                            current_execution_position..current_execution_position,
19882                        )?;
19883
19884                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19885                    })?;
19886
19887                    let range =
19888                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19889
19890                    project.inline_values(buffer, range, cx)
19891                })
19892                .ok()
19893                .flatten()?
19894                .await
19895                .context("refreshing debugger inlays")
19896                .log_err()?;
19897
19898            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19899
19900            for (buffer_id, inline_value) in inline_values
19901                .into_iter()
19902                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19903            {
19904                buffer_inline_values
19905                    .entry(buffer_id)
19906                    .or_default()
19907                    .push(inline_value);
19908            }
19909
19910            editor
19911                .update(cx, |editor, cx| {
19912                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19913                    let mut new_inlays = Vec::default();
19914
19915                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19916                        let buffer_id = buffer_snapshot.remote_id();
19917                        buffer_inline_values
19918                            .get(&buffer_id)
19919                            .into_iter()
19920                            .flatten()
19921                            .for_each(|hint| {
19922                                let inlay = Inlay::debugger(
19923                                    post_inc(&mut editor.next_inlay_id),
19924                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19925                                    hint.text(),
19926                                );
19927                                if !inlay.text.chars().contains(&'\n') {
19928                                    new_inlays.push(inlay);
19929                                }
19930                            });
19931                    }
19932
19933                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19934                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19935
19936                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19937                })
19938                .ok()?;
19939            Some(())
19940        });
19941    }
19942
19943    fn on_buffer_event(
19944        &mut self,
19945        multibuffer: &Entity<MultiBuffer>,
19946        event: &multi_buffer::Event,
19947        window: &mut Window,
19948        cx: &mut Context<Self>,
19949    ) {
19950        match event {
19951            multi_buffer::Event::Edited {
19952                singleton_buffer_edited,
19953                edited_buffer,
19954            } => {
19955                self.scrollbar_marker_state.dirty = true;
19956                self.active_indent_guides_state.dirty = true;
19957                self.refresh_active_diagnostics(cx);
19958                self.refresh_code_actions(window, cx);
19959                self.refresh_selected_text_highlights(true, window, cx);
19960                self.refresh_single_line_folds(window, cx);
19961                refresh_matching_bracket_highlights(self, window, cx);
19962                if self.has_active_edit_prediction() {
19963                    self.update_visible_edit_prediction(window, cx);
19964                }
19965                if let Some(project) = self.project.as_ref() {
19966                    if let Some(edited_buffer) = edited_buffer {
19967                        project.update(cx, |project, cx| {
19968                            self.registered_buffers
19969                                .entry(edited_buffer.read(cx).remote_id())
19970                                .or_insert_with(|| {
19971                                    project
19972                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19973                                });
19974                        });
19975                    }
19976                }
19977                cx.emit(EditorEvent::BufferEdited);
19978                cx.emit(SearchEvent::MatchesInvalidated);
19979
19980                if let Some(buffer) = edited_buffer {
19981                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
19982                }
19983
19984                if *singleton_buffer_edited {
19985                    if let Some(buffer) = edited_buffer {
19986                        if buffer.read(cx).file().is_none() {
19987                            cx.emit(EditorEvent::TitleChanged);
19988                        }
19989                    }
19990                    if let Some(project) = &self.project {
19991                        #[allow(clippy::mutable_key_type)]
19992                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19993                            multibuffer
19994                                .all_buffers()
19995                                .into_iter()
19996                                .filter_map(|buffer| {
19997                                    buffer.update(cx, |buffer, cx| {
19998                                        let language = buffer.language()?;
19999                                        let should_discard = project.update(cx, |project, cx| {
20000                                            project.is_local()
20001                                                && !project.has_language_servers_for(buffer, cx)
20002                                        });
20003                                        should_discard.not().then_some(language.clone())
20004                                    })
20005                                })
20006                                .collect::<HashSet<_>>()
20007                        });
20008                        if !languages_affected.is_empty() {
20009                            self.refresh_inlay_hints(
20010                                InlayHintRefreshReason::BufferEdited(languages_affected),
20011                                cx,
20012                            );
20013                        }
20014                    }
20015                }
20016
20017                let Some(project) = &self.project else { return };
20018                let (telemetry, is_via_ssh) = {
20019                    let project = project.read(cx);
20020                    let telemetry = project.client().telemetry().clone();
20021                    let is_via_ssh = project.is_via_ssh();
20022                    (telemetry, is_via_ssh)
20023                };
20024                refresh_linked_ranges(self, window, cx);
20025                telemetry.log_edit_event("editor", is_via_ssh);
20026            }
20027            multi_buffer::Event::ExcerptsAdded {
20028                buffer,
20029                predecessor,
20030                excerpts,
20031            } => {
20032                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20033                let buffer_id = buffer.read(cx).remote_id();
20034                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
20035                    if let Some(project) = &self.project {
20036                        update_uncommitted_diff_for_buffer(
20037                            cx.entity(),
20038                            project,
20039                            [buffer.clone()],
20040                            self.buffer.clone(),
20041                            cx,
20042                        )
20043                        .detach();
20044                    }
20045                }
20046                self.update_lsp_data(false, Some(buffer_id), window, cx);
20047                cx.emit(EditorEvent::ExcerptsAdded {
20048                    buffer: buffer.clone(),
20049                    predecessor: *predecessor,
20050                    excerpts: excerpts.clone(),
20051                });
20052                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20053            }
20054            multi_buffer::Event::ExcerptsRemoved {
20055                ids,
20056                removed_buffer_ids,
20057            } => {
20058                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20059                let buffer = self.buffer.read(cx);
20060                self.registered_buffers
20061                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20062                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20063                cx.emit(EditorEvent::ExcerptsRemoved {
20064                    ids: ids.clone(),
20065                    removed_buffer_ids: removed_buffer_ids.clone(),
20066                });
20067            }
20068            multi_buffer::Event::ExcerptsEdited {
20069                excerpt_ids,
20070                buffer_ids,
20071            } => {
20072                self.display_map.update(cx, |map, cx| {
20073                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20074                });
20075                cx.emit(EditorEvent::ExcerptsEdited {
20076                    ids: excerpt_ids.clone(),
20077                });
20078            }
20079            multi_buffer::Event::ExcerptsExpanded { ids } => {
20080                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20081                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20082            }
20083            multi_buffer::Event::Reparsed(buffer_id) => {
20084                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20085                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20086
20087                cx.emit(EditorEvent::Reparsed(*buffer_id));
20088            }
20089            multi_buffer::Event::DiffHunksToggled => {
20090                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20091            }
20092            multi_buffer::Event::LanguageChanged(buffer_id) => {
20093                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20094                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20095                cx.emit(EditorEvent::Reparsed(*buffer_id));
20096                cx.notify();
20097            }
20098            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20099            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20100            multi_buffer::Event::FileHandleChanged
20101            | multi_buffer::Event::Reloaded
20102            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20103            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
20104            multi_buffer::Event::DiagnosticsUpdated => {
20105                self.update_diagnostics_state(window, cx);
20106            }
20107            _ => {}
20108        };
20109    }
20110
20111    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20112        if !self.diagnostics_enabled() {
20113            return;
20114        }
20115        self.refresh_active_diagnostics(cx);
20116        self.refresh_inline_diagnostics(true, window, cx);
20117        self.scrollbar_marker_state.dirty = true;
20118        cx.notify();
20119    }
20120
20121    pub fn start_temporary_diff_override(&mut self) {
20122        self.load_diff_task.take();
20123        self.temporary_diff_override = true;
20124    }
20125
20126    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20127        self.temporary_diff_override = false;
20128        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20129        self.buffer.update(cx, |buffer, cx| {
20130            buffer.set_all_diff_hunks_collapsed(cx);
20131        });
20132
20133        if let Some(project) = self.project.clone() {
20134            self.load_diff_task = Some(
20135                update_uncommitted_diff_for_buffer(
20136                    cx.entity(),
20137                    &project,
20138                    self.buffer.read(cx).all_buffers(),
20139                    self.buffer.clone(),
20140                    cx,
20141                )
20142                .shared(),
20143            );
20144        }
20145    }
20146
20147    fn on_display_map_changed(
20148        &mut self,
20149        _: Entity<DisplayMap>,
20150        _: &mut Window,
20151        cx: &mut Context<Self>,
20152    ) {
20153        cx.notify();
20154    }
20155
20156    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20157        if self.diagnostics_enabled() {
20158            let new_severity = EditorSettings::get_global(cx)
20159                .diagnostics_max_severity
20160                .unwrap_or(DiagnosticSeverity::Hint);
20161            self.set_max_diagnostics_severity(new_severity, cx);
20162        }
20163        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20164        self.update_edit_prediction_settings(cx);
20165        self.refresh_edit_prediction(true, false, window, cx);
20166        self.refresh_inline_values(cx);
20167        self.refresh_inlay_hints(
20168            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20169                self.selections.newest_anchor().head(),
20170                &self.buffer.read(cx).snapshot(cx),
20171                cx,
20172            )),
20173            cx,
20174        );
20175
20176        let old_cursor_shape = self.cursor_shape;
20177
20178        {
20179            let editor_settings = EditorSettings::get_global(cx);
20180            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20181            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20182            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20183            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20184        }
20185
20186        if old_cursor_shape != self.cursor_shape {
20187            cx.emit(EditorEvent::CursorShapeChanged);
20188        }
20189
20190        let project_settings = ProjectSettings::get_global(cx);
20191        self.serialize_dirty_buffers =
20192            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20193
20194        if self.mode.is_full() {
20195            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20196            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20197            if self.show_inline_diagnostics != show_inline_diagnostics {
20198                self.show_inline_diagnostics = show_inline_diagnostics;
20199                self.refresh_inline_diagnostics(false, window, cx);
20200            }
20201
20202            if self.git_blame_inline_enabled != inline_blame_enabled {
20203                self.toggle_git_blame_inline_internal(false, window, cx);
20204            }
20205
20206            let minimap_settings = EditorSettings::get_global(cx).minimap;
20207            if self.minimap_visibility != MinimapVisibility::Disabled {
20208                if self.minimap_visibility.settings_visibility()
20209                    != minimap_settings.minimap_enabled()
20210                {
20211                    self.set_minimap_visibility(
20212                        MinimapVisibility::for_mode(self.mode(), cx),
20213                        window,
20214                        cx,
20215                    );
20216                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20217                    minimap_entity.update(cx, |minimap_editor, cx| {
20218                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20219                    })
20220                }
20221            }
20222        }
20223
20224        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20225            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20226        }) {
20227            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20228                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20229            }
20230            self.refresh_colors(false, None, window, cx);
20231        }
20232
20233        cx.notify();
20234    }
20235
20236    pub fn set_searchable(&mut self, searchable: bool) {
20237        self.searchable = searchable;
20238    }
20239
20240    pub fn searchable(&self) -> bool {
20241        self.searchable
20242    }
20243
20244    fn open_proposed_changes_editor(
20245        &mut self,
20246        _: &OpenProposedChangesEditor,
20247        window: &mut Window,
20248        cx: &mut Context<Self>,
20249    ) {
20250        let Some(workspace) = self.workspace() else {
20251            cx.propagate();
20252            return;
20253        };
20254
20255        let selections = self.selections.all::<usize>(cx);
20256        let multi_buffer = self.buffer.read(cx);
20257        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20258        let mut new_selections_by_buffer = HashMap::default();
20259        for selection in selections {
20260            for (buffer, range, _) in
20261                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20262            {
20263                let mut range = range.to_point(buffer);
20264                range.start.column = 0;
20265                range.end.column = buffer.line_len(range.end.row);
20266                new_selections_by_buffer
20267                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20268                    .or_insert(Vec::new())
20269                    .push(range)
20270            }
20271        }
20272
20273        let proposed_changes_buffers = new_selections_by_buffer
20274            .into_iter()
20275            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20276            .collect::<Vec<_>>();
20277        let proposed_changes_editor = cx.new(|cx| {
20278            ProposedChangesEditor::new(
20279                "Proposed changes",
20280                proposed_changes_buffers,
20281                self.project.clone(),
20282                window,
20283                cx,
20284            )
20285        });
20286
20287        window.defer(cx, move |window, cx| {
20288            workspace.update(cx, |workspace, cx| {
20289                workspace.active_pane().update(cx, |pane, cx| {
20290                    pane.add_item(
20291                        Box::new(proposed_changes_editor),
20292                        true,
20293                        true,
20294                        None,
20295                        window,
20296                        cx,
20297                    );
20298                });
20299            });
20300        });
20301    }
20302
20303    pub fn open_excerpts_in_split(
20304        &mut self,
20305        _: &OpenExcerptsSplit,
20306        window: &mut Window,
20307        cx: &mut Context<Self>,
20308    ) {
20309        self.open_excerpts_common(None, true, window, cx)
20310    }
20311
20312    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20313        self.open_excerpts_common(None, false, window, cx)
20314    }
20315
20316    fn open_excerpts_common(
20317        &mut self,
20318        jump_data: Option<JumpData>,
20319        split: bool,
20320        window: &mut Window,
20321        cx: &mut Context<Self>,
20322    ) {
20323        let Some(workspace) = self.workspace() else {
20324            cx.propagate();
20325            return;
20326        };
20327
20328        if self.buffer.read(cx).is_singleton() {
20329            cx.propagate();
20330            return;
20331        }
20332
20333        let mut new_selections_by_buffer = HashMap::default();
20334        match &jump_data {
20335            Some(JumpData::MultiBufferPoint {
20336                excerpt_id,
20337                position,
20338                anchor,
20339                line_offset_from_top,
20340            }) => {
20341                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20342                if let Some(buffer) = multi_buffer_snapshot
20343                    .buffer_id_for_excerpt(*excerpt_id)
20344                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20345                {
20346                    let buffer_snapshot = buffer.read(cx).snapshot();
20347                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20348                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20349                    } else {
20350                        buffer_snapshot.clip_point(*position, Bias::Left)
20351                    };
20352                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20353                    new_selections_by_buffer.insert(
20354                        buffer,
20355                        (
20356                            vec![jump_to_offset..jump_to_offset],
20357                            Some(*line_offset_from_top),
20358                        ),
20359                    );
20360                }
20361            }
20362            Some(JumpData::MultiBufferRow {
20363                row,
20364                line_offset_from_top,
20365            }) => {
20366                let point = MultiBufferPoint::new(row.0, 0);
20367                if let Some((buffer, buffer_point, _)) =
20368                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20369                {
20370                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20371                    new_selections_by_buffer
20372                        .entry(buffer)
20373                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20374                        .0
20375                        .push(buffer_offset..buffer_offset)
20376                }
20377            }
20378            None => {
20379                let selections = self.selections.all::<usize>(cx);
20380                let multi_buffer = self.buffer.read(cx);
20381                for selection in selections {
20382                    for (snapshot, range, _, anchor) in multi_buffer
20383                        .snapshot(cx)
20384                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20385                    {
20386                        if let Some(anchor) = anchor {
20387                            // selection is in a deleted hunk
20388                            let Some(buffer_id) = anchor.buffer_id else {
20389                                continue;
20390                            };
20391                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
20392                                continue;
20393                            };
20394                            let offset = text::ToOffset::to_offset(
20395                                &anchor.text_anchor,
20396                                &buffer_handle.read(cx).snapshot(),
20397                            );
20398                            let range = offset..offset;
20399                            new_selections_by_buffer
20400                                .entry(buffer_handle)
20401                                .or_insert((Vec::new(), None))
20402                                .0
20403                                .push(range)
20404                        } else {
20405                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20406                            else {
20407                                continue;
20408                            };
20409                            new_selections_by_buffer
20410                                .entry(buffer_handle)
20411                                .or_insert((Vec::new(), None))
20412                                .0
20413                                .push(range)
20414                        }
20415                    }
20416                }
20417            }
20418        }
20419
20420        new_selections_by_buffer
20421            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20422
20423        if new_selections_by_buffer.is_empty() {
20424            return;
20425        }
20426
20427        // We defer the pane interaction because we ourselves are a workspace item
20428        // and activating a new item causes the pane to call a method on us reentrantly,
20429        // which panics if we're on the stack.
20430        window.defer(cx, move |window, cx| {
20431            workspace.update(cx, |workspace, cx| {
20432                let pane = if split {
20433                    workspace.adjacent_pane(window, cx)
20434                } else {
20435                    workspace.active_pane().clone()
20436                };
20437
20438                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20439                    let editor = buffer
20440                        .read(cx)
20441                        .file()
20442                        .is_none()
20443                        .then(|| {
20444                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20445                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20446                            // Instead, we try to activate the existing editor in the pane first.
20447                            let (editor, pane_item_index) =
20448                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20449                                    let editor = item.downcast::<Editor>()?;
20450                                    let singleton_buffer =
20451                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20452                                    if singleton_buffer == buffer {
20453                                        Some((editor, i))
20454                                    } else {
20455                                        None
20456                                    }
20457                                })?;
20458                            pane.update(cx, |pane, cx| {
20459                                pane.activate_item(pane_item_index, true, true, window, cx)
20460                            });
20461                            Some(editor)
20462                        })
20463                        .flatten()
20464                        .unwrap_or_else(|| {
20465                            workspace.open_project_item::<Self>(
20466                                pane.clone(),
20467                                buffer,
20468                                true,
20469                                true,
20470                                window,
20471                                cx,
20472                            )
20473                        });
20474
20475                    editor.update(cx, |editor, cx| {
20476                        let autoscroll = match scroll_offset {
20477                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20478                            None => Autoscroll::newest(),
20479                        };
20480                        let nav_history = editor.nav_history.take();
20481                        editor.change_selections(
20482                            SelectionEffects::scroll(autoscroll),
20483                            window,
20484                            cx,
20485                            |s| {
20486                                s.select_ranges(ranges);
20487                            },
20488                        );
20489                        editor.nav_history = nav_history;
20490                    });
20491                }
20492            })
20493        });
20494    }
20495
20496    // For now, don't allow opening excerpts in buffers that aren't backed by
20497    // regular project files.
20498    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20499        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
20500    }
20501
20502    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20503        let snapshot = self.buffer.read(cx).read(cx);
20504        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20505        Some(
20506            ranges
20507                .iter()
20508                .map(move |range| {
20509                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20510                })
20511                .collect(),
20512        )
20513    }
20514
20515    fn selection_replacement_ranges(
20516        &self,
20517        range: Range<OffsetUtf16>,
20518        cx: &mut App,
20519    ) -> Vec<Range<OffsetUtf16>> {
20520        let selections = self.selections.all::<OffsetUtf16>(cx);
20521        let newest_selection = selections
20522            .iter()
20523            .max_by_key(|selection| selection.id)
20524            .unwrap();
20525        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20526        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20527        let snapshot = self.buffer.read(cx).read(cx);
20528        selections
20529            .into_iter()
20530            .map(|mut selection| {
20531                selection.start.0 =
20532                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20533                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20534                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20535                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20536            })
20537            .collect()
20538    }
20539
20540    fn report_editor_event(
20541        &self,
20542        event_type: &'static str,
20543        file_extension: Option<String>,
20544        cx: &App,
20545    ) {
20546        if cfg!(any(test, feature = "test-support")) {
20547            return;
20548        }
20549
20550        let Some(project) = &self.project else { return };
20551
20552        // If None, we are in a file without an extension
20553        let file = self
20554            .buffer
20555            .read(cx)
20556            .as_singleton()
20557            .and_then(|b| b.read(cx).file());
20558        let file_extension = file_extension.or(file
20559            .as_ref()
20560            .and_then(|file| Path::new(file.file_name(cx)).extension())
20561            .and_then(|e| e.to_str())
20562            .map(|a| a.to_string()));
20563
20564        let vim_mode = vim_enabled(cx);
20565
20566        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20567        let copilot_enabled = edit_predictions_provider
20568            == language::language_settings::EditPredictionProvider::Copilot;
20569        let copilot_enabled_for_language = self
20570            .buffer
20571            .read(cx)
20572            .language_settings(cx)
20573            .show_edit_predictions;
20574
20575        let project = project.read(cx);
20576        telemetry::event!(
20577            event_type,
20578            file_extension,
20579            vim_mode,
20580            copilot_enabled,
20581            copilot_enabled_for_language,
20582            edit_predictions_provider,
20583            is_via_ssh = project.is_via_ssh(),
20584        );
20585    }
20586
20587    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20588    /// with each line being an array of {text, highlight} objects.
20589    fn copy_highlight_json(
20590        &mut self,
20591        _: &CopyHighlightJson,
20592        window: &mut Window,
20593        cx: &mut Context<Self>,
20594    ) {
20595        #[derive(Serialize)]
20596        struct Chunk<'a> {
20597            text: String,
20598            highlight: Option<&'a str>,
20599        }
20600
20601        let snapshot = self.buffer.read(cx).snapshot(cx);
20602        let range = self
20603            .selected_text_range(false, window, cx)
20604            .and_then(|selection| {
20605                if selection.range.is_empty() {
20606                    None
20607                } else {
20608                    Some(selection.range)
20609                }
20610            })
20611            .unwrap_or_else(|| 0..snapshot.len());
20612
20613        let chunks = snapshot.chunks(range, true);
20614        let mut lines = Vec::new();
20615        let mut line: VecDeque<Chunk> = VecDeque::new();
20616
20617        let Some(style) = self.style.as_ref() else {
20618            return;
20619        };
20620
20621        for chunk in chunks {
20622            let highlight = chunk
20623                .syntax_highlight_id
20624                .and_then(|id| id.name(&style.syntax));
20625            let mut chunk_lines = chunk.text.split('\n').peekable();
20626            while let Some(text) = chunk_lines.next() {
20627                let mut merged_with_last_token = false;
20628                if let Some(last_token) = line.back_mut() {
20629                    if last_token.highlight == highlight {
20630                        last_token.text.push_str(text);
20631                        merged_with_last_token = true;
20632                    }
20633                }
20634
20635                if !merged_with_last_token {
20636                    line.push_back(Chunk {
20637                        text: text.into(),
20638                        highlight,
20639                    });
20640                }
20641
20642                if chunk_lines.peek().is_some() {
20643                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20644                        line.pop_front();
20645                    }
20646                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20647                        line.pop_back();
20648                    }
20649
20650                    lines.push(mem::take(&mut line));
20651                }
20652            }
20653        }
20654
20655        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20656            return;
20657        };
20658        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20659    }
20660
20661    pub fn open_context_menu(
20662        &mut self,
20663        _: &OpenContextMenu,
20664        window: &mut Window,
20665        cx: &mut Context<Self>,
20666    ) {
20667        self.request_autoscroll(Autoscroll::newest(), cx);
20668        let position = self.selections.newest_display(cx).start;
20669        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20670    }
20671
20672    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20673        &self.inlay_hint_cache
20674    }
20675
20676    pub fn replay_insert_event(
20677        &mut self,
20678        text: &str,
20679        relative_utf16_range: Option<Range<isize>>,
20680        window: &mut Window,
20681        cx: &mut Context<Self>,
20682    ) {
20683        if !self.input_enabled {
20684            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20685            return;
20686        }
20687        if let Some(relative_utf16_range) = relative_utf16_range {
20688            let selections = self.selections.all::<OffsetUtf16>(cx);
20689            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20690                let new_ranges = selections.into_iter().map(|range| {
20691                    let start = OffsetUtf16(
20692                        range
20693                            .head()
20694                            .0
20695                            .saturating_add_signed(relative_utf16_range.start),
20696                    );
20697                    let end = OffsetUtf16(
20698                        range
20699                            .head()
20700                            .0
20701                            .saturating_add_signed(relative_utf16_range.end),
20702                    );
20703                    start..end
20704                });
20705                s.select_ranges(new_ranges);
20706            });
20707        }
20708
20709        self.handle_input(text, window, cx);
20710    }
20711
20712    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20713        let Some(provider) = self.semantics_provider.as_ref() else {
20714            return false;
20715        };
20716
20717        let mut supports = false;
20718        self.buffer().update(cx, |this, cx| {
20719            this.for_each_buffer(|buffer| {
20720                supports |= provider.supports_inlay_hints(buffer, cx);
20721            });
20722        });
20723
20724        supports
20725    }
20726
20727    pub fn is_focused(&self, window: &Window) -> bool {
20728        self.focus_handle.is_focused(window)
20729    }
20730
20731    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20732        cx.emit(EditorEvent::Focused);
20733
20734        if let Some(descendant) = self
20735            .last_focused_descendant
20736            .take()
20737            .and_then(|descendant| descendant.upgrade())
20738        {
20739            window.focus(&descendant);
20740        } else {
20741            if let Some(blame) = self.blame.as_ref() {
20742                blame.update(cx, GitBlame::focus)
20743            }
20744
20745            self.blink_manager.update(cx, BlinkManager::enable);
20746            self.show_cursor_names(window, cx);
20747            self.buffer.update(cx, |buffer, cx| {
20748                buffer.finalize_last_transaction(cx);
20749                if self.leader_id.is_none() {
20750                    buffer.set_active_selections(
20751                        &self.selections.disjoint_anchors(),
20752                        self.selections.line_mode,
20753                        self.cursor_shape,
20754                        cx,
20755                    );
20756                }
20757            });
20758        }
20759    }
20760
20761    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20762        cx.emit(EditorEvent::FocusedIn)
20763    }
20764
20765    fn handle_focus_out(
20766        &mut self,
20767        event: FocusOutEvent,
20768        _window: &mut Window,
20769        cx: &mut Context<Self>,
20770    ) {
20771        if event.blurred != self.focus_handle {
20772            self.last_focused_descendant = Some(event.blurred);
20773        }
20774        self.selection_drag_state = SelectionDragState::None;
20775        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20776    }
20777
20778    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20779        self.blink_manager.update(cx, BlinkManager::disable);
20780        self.buffer
20781            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20782
20783        if let Some(blame) = self.blame.as_ref() {
20784            blame.update(cx, GitBlame::blur)
20785        }
20786        if !self.hover_state.focused(window, cx) {
20787            hide_hover(self, cx);
20788        }
20789        if !self
20790            .context_menu
20791            .borrow()
20792            .as_ref()
20793            .is_some_and(|context_menu| context_menu.focused(window, cx))
20794        {
20795            self.hide_context_menu(window, cx);
20796        }
20797        self.discard_edit_prediction(false, cx);
20798        cx.emit(EditorEvent::Blurred);
20799        cx.notify();
20800    }
20801
20802    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20803        let mut pending: String = window
20804            .pending_input_keystrokes()
20805            .into_iter()
20806            .flatten()
20807            .filter_map(|keystroke| {
20808                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20809                    keystroke.key_char.clone()
20810                } else {
20811                    None
20812                }
20813            })
20814            .collect();
20815
20816        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20817            pending = "".to_string();
20818        }
20819
20820        let existing_pending = self
20821            .text_highlights::<PendingInput>(cx)
20822            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
20823        if existing_pending.is_none() && pending.is_empty() {
20824            return;
20825        }
20826        let transaction =
20827            self.transact(window, cx, |this, window, cx| {
20828                let selections = this.selections.all::<usize>(cx);
20829                let edits = selections
20830                    .iter()
20831                    .map(|selection| (selection.end..selection.end, pending.clone()));
20832                this.edit(edits, cx);
20833                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20834                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20835                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20836                    }));
20837                });
20838                if let Some(existing_ranges) = existing_pending {
20839                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20840                    this.edit(edits, cx);
20841                }
20842            });
20843
20844        let snapshot = self.snapshot(window, cx);
20845        let ranges = self
20846            .selections
20847            .all::<usize>(cx)
20848            .into_iter()
20849            .map(|selection| {
20850                snapshot.buffer_snapshot.anchor_after(selection.end)
20851                    ..snapshot
20852                        .buffer_snapshot
20853                        .anchor_before(selection.end + pending.len())
20854            })
20855            .collect();
20856
20857        if pending.is_empty() {
20858            self.clear_highlights::<PendingInput>(cx);
20859        } else {
20860            self.highlight_text::<PendingInput>(
20861                ranges,
20862                HighlightStyle {
20863                    underline: Some(UnderlineStyle {
20864                        thickness: px(1.),
20865                        color: None,
20866                        wavy: false,
20867                    }),
20868                    ..Default::default()
20869                },
20870                cx,
20871            );
20872        }
20873
20874        self.ime_transaction = self.ime_transaction.or(transaction);
20875        if let Some(transaction) = self.ime_transaction {
20876            self.buffer.update(cx, |buffer, cx| {
20877                buffer.group_until_transaction(transaction, cx);
20878            });
20879        }
20880
20881        if self.text_highlights::<PendingInput>(cx).is_none() {
20882            self.ime_transaction.take();
20883        }
20884    }
20885
20886    pub fn register_action_renderer(
20887        &mut self,
20888        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20889    ) -> Subscription {
20890        let id = self.next_editor_action_id.post_inc();
20891        self.editor_actions
20892            .borrow_mut()
20893            .insert(id, Box::new(listener));
20894
20895        let editor_actions = self.editor_actions.clone();
20896        Subscription::new(move || {
20897            editor_actions.borrow_mut().remove(&id);
20898        })
20899    }
20900
20901    pub fn register_action<A: Action>(
20902        &mut self,
20903        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20904    ) -> Subscription {
20905        let id = self.next_editor_action_id.post_inc();
20906        let listener = Arc::new(listener);
20907        self.editor_actions.borrow_mut().insert(
20908            id,
20909            Box::new(move |_, window, _| {
20910                let listener = listener.clone();
20911                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20912                    let action = action.downcast_ref().unwrap();
20913                    if phase == DispatchPhase::Bubble {
20914                        listener(action, window, cx)
20915                    }
20916                })
20917            }),
20918        );
20919
20920        let editor_actions = self.editor_actions.clone();
20921        Subscription::new(move || {
20922            editor_actions.borrow_mut().remove(&id);
20923        })
20924    }
20925
20926    pub fn file_header_size(&self) -> u32 {
20927        FILE_HEADER_HEIGHT
20928    }
20929
20930    pub fn restore(
20931        &mut self,
20932        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20933        window: &mut Window,
20934        cx: &mut Context<Self>,
20935    ) {
20936        let workspace = self.workspace();
20937        let project = self.project.as_ref();
20938        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20939            let mut tasks = Vec::new();
20940            for (buffer_id, changes) in revert_changes {
20941                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20942                    buffer.update(cx, |buffer, cx| {
20943                        buffer.edit(
20944                            changes
20945                                .into_iter()
20946                                .map(|(range, text)| (range, text.to_string())),
20947                            None,
20948                            cx,
20949                        );
20950                    });
20951
20952                    if let Some(project) =
20953                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20954                    {
20955                        project.update(cx, |project, cx| {
20956                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20957                        })
20958                    }
20959                }
20960            }
20961            tasks
20962        });
20963        cx.spawn_in(window, async move |_, cx| {
20964            for (buffer, task) in save_tasks {
20965                let result = task.await;
20966                if result.is_err() {
20967                    let Some(path) = buffer
20968                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20969                        .ok()
20970                    else {
20971                        continue;
20972                    };
20973                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20974                        let Some(task) = cx
20975                            .update_window_entity(&workspace, |workspace, window, cx| {
20976                                workspace
20977                                    .open_path_preview(path, None, false, false, false, window, cx)
20978                            })
20979                            .ok()
20980                        else {
20981                            continue;
20982                        };
20983                        task.await.log_err();
20984                    }
20985                }
20986            }
20987        })
20988        .detach();
20989        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
20990            selections.refresh()
20991        });
20992    }
20993
20994    pub fn to_pixel_point(
20995        &self,
20996        source: multi_buffer::Anchor,
20997        editor_snapshot: &EditorSnapshot,
20998        window: &mut Window,
20999    ) -> Option<gpui::Point<Pixels>> {
21000        let source_point = source.to_display_point(editor_snapshot);
21001        self.display_to_pixel_point(source_point, editor_snapshot, window)
21002    }
21003
21004    pub fn display_to_pixel_point(
21005        &self,
21006        source: DisplayPoint,
21007        editor_snapshot: &EditorSnapshot,
21008        window: &mut Window,
21009    ) -> Option<gpui::Point<Pixels>> {
21010        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21011        let text_layout_details = self.text_layout_details(window);
21012        let scroll_top = text_layout_details
21013            .scroll_anchor
21014            .scroll_position(editor_snapshot)
21015            .y;
21016
21017        if source.row().as_f32() < scroll_top.floor() {
21018            return None;
21019        }
21020        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21021        let source_y = line_height * (source.row().as_f32() - scroll_top);
21022        Some(gpui::Point::new(source_x, source_y))
21023    }
21024
21025    pub fn has_visible_completions_menu(&self) -> bool {
21026        !self.edit_prediction_preview_is_active()
21027            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
21028                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21029            })
21030    }
21031
21032    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21033        if self.mode.is_minimap() {
21034            return;
21035        }
21036        self.addons
21037            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21038    }
21039
21040    pub fn unregister_addon<T: Addon>(&mut self) {
21041        self.addons.remove(&std::any::TypeId::of::<T>());
21042    }
21043
21044    pub fn addon<T: Addon>(&self) -> Option<&T> {
21045        let type_id = std::any::TypeId::of::<T>();
21046        self.addons
21047            .get(&type_id)
21048            .and_then(|item| item.to_any().downcast_ref::<T>())
21049    }
21050
21051    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21052        let type_id = std::any::TypeId::of::<T>();
21053        self.addons
21054            .get_mut(&type_id)
21055            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21056    }
21057
21058    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21059        let text_layout_details = self.text_layout_details(window);
21060        let style = &text_layout_details.editor_style;
21061        let font_id = window.text_system().resolve_font(&style.text.font());
21062        let font_size = style.text.font_size.to_pixels(window.rem_size());
21063        let line_height = style.text.line_height_in_pixels(window.rem_size());
21064        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21065        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21066
21067        CharacterDimensions {
21068            em_width,
21069            em_advance,
21070            line_height,
21071        }
21072    }
21073
21074    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21075        self.load_diff_task.clone()
21076    }
21077
21078    fn read_metadata_from_db(
21079        &mut self,
21080        item_id: u64,
21081        workspace_id: WorkspaceId,
21082        window: &mut Window,
21083        cx: &mut Context<Editor>,
21084    ) {
21085        if self.is_singleton(cx)
21086            && !self.mode.is_minimap()
21087            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21088        {
21089            let buffer_snapshot = OnceCell::new();
21090
21091            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
21092                if !folds.is_empty() {
21093                    let snapshot =
21094                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21095                    self.fold_ranges(
21096                        folds
21097                            .into_iter()
21098                            .map(|(start, end)| {
21099                                snapshot.clip_offset(start, Bias::Left)
21100                                    ..snapshot.clip_offset(end, Bias::Right)
21101                            })
21102                            .collect(),
21103                        false,
21104                        window,
21105                        cx,
21106                    );
21107                }
21108            }
21109
21110            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
21111                if !selections.is_empty() {
21112                    let snapshot =
21113                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21114                    // skip adding the initial selection to selection history
21115                    self.selection_history.mode = SelectionHistoryMode::Skipping;
21116                    self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21117                        s.select_ranges(selections.into_iter().map(|(start, end)| {
21118                            snapshot.clip_offset(start, Bias::Left)
21119                                ..snapshot.clip_offset(end, Bias::Right)
21120                        }));
21121                    });
21122                    self.selection_history.mode = SelectionHistoryMode::Normal;
21123                }
21124            };
21125        }
21126
21127        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21128    }
21129
21130    fn update_lsp_data(
21131        &mut self,
21132        ignore_cache: bool,
21133        for_buffer: Option<BufferId>,
21134        window: &mut Window,
21135        cx: &mut Context<'_, Self>,
21136    ) {
21137        self.pull_diagnostics(for_buffer, window, cx);
21138        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21139    }
21140}
21141
21142fn vim_enabled(cx: &App) -> bool {
21143    cx.global::<SettingsStore>()
21144        .raw_user_settings()
21145        .get("vim_mode")
21146        == Some(&serde_json::Value::Bool(true))
21147}
21148
21149fn process_completion_for_edit(
21150    completion: &Completion,
21151    intent: CompletionIntent,
21152    buffer: &Entity<Buffer>,
21153    cursor_position: &text::Anchor,
21154    cx: &mut Context<Editor>,
21155) -> CompletionEdit {
21156    let buffer = buffer.read(cx);
21157    let buffer_snapshot = buffer.snapshot();
21158    let (snippet, new_text) = if completion.is_snippet() {
21159        // Workaround for typescript language server issues so that methods don't expand within
21160        // strings and functions with type expressions. The previous point is used because the query
21161        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21162        let mut snippet_source = completion.new_text.clone();
21163        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21164        previous_point.column = previous_point.column.saturating_sub(1);
21165        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
21166            if scope.prefers_label_for_snippet_in_completion() {
21167                if let Some(label) = completion.label() {
21168                    if matches!(
21169                        completion.kind(),
21170                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21171                    ) {
21172                        snippet_source = label;
21173                    }
21174                }
21175            }
21176        }
21177        match Snippet::parse(&snippet_source).log_err() {
21178            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21179            None => (None, completion.new_text.clone()),
21180        }
21181    } else {
21182        (None, completion.new_text.clone())
21183    };
21184
21185    let mut range_to_replace = {
21186        let replace_range = &completion.replace_range;
21187        if let CompletionSource::Lsp {
21188            insert_range: Some(insert_range),
21189            ..
21190        } = &completion.source
21191        {
21192            debug_assert_eq!(
21193                insert_range.start, replace_range.start,
21194                "insert_range and replace_range should start at the same position"
21195            );
21196            debug_assert!(
21197                insert_range
21198                    .start
21199                    .cmp(&cursor_position, &buffer_snapshot)
21200                    .is_le(),
21201                "insert_range should start before or at cursor position"
21202            );
21203            debug_assert!(
21204                replace_range
21205                    .start
21206                    .cmp(&cursor_position, &buffer_snapshot)
21207                    .is_le(),
21208                "replace_range should start before or at cursor position"
21209            );
21210
21211            let should_replace = match intent {
21212                CompletionIntent::CompleteWithInsert => false,
21213                CompletionIntent::CompleteWithReplace => true,
21214                CompletionIntent::Complete | CompletionIntent::Compose => {
21215                    let insert_mode =
21216                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21217                            .completions
21218                            .lsp_insert_mode;
21219                    match insert_mode {
21220                        LspInsertMode::Insert => false,
21221                        LspInsertMode::Replace => true,
21222                        LspInsertMode::ReplaceSubsequence => {
21223                            let mut text_to_replace = buffer.chars_for_range(
21224                                buffer.anchor_before(replace_range.start)
21225                                    ..buffer.anchor_after(replace_range.end),
21226                            );
21227                            let mut current_needle = text_to_replace.next();
21228                            for haystack_ch in completion.label.text.chars() {
21229                                if let Some(needle_ch) = current_needle {
21230                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
21231                                        current_needle = text_to_replace.next();
21232                                    }
21233                                }
21234                            }
21235                            current_needle.is_none()
21236                        }
21237                        LspInsertMode::ReplaceSuffix => {
21238                            if replace_range
21239                                .end
21240                                .cmp(&cursor_position, &buffer_snapshot)
21241                                .is_gt()
21242                            {
21243                                let range_after_cursor = *cursor_position..replace_range.end;
21244                                let text_after_cursor = buffer
21245                                    .text_for_range(
21246                                        buffer.anchor_before(range_after_cursor.start)
21247                                            ..buffer.anchor_after(range_after_cursor.end),
21248                                    )
21249                                    .collect::<String>()
21250                                    .to_ascii_lowercase();
21251                                completion
21252                                    .label
21253                                    .text
21254                                    .to_ascii_lowercase()
21255                                    .ends_with(&text_after_cursor)
21256                            } else {
21257                                true
21258                            }
21259                        }
21260                    }
21261                }
21262            };
21263
21264            if should_replace {
21265                replace_range.clone()
21266            } else {
21267                insert_range.clone()
21268            }
21269        } else {
21270            replace_range.clone()
21271        }
21272    };
21273
21274    if range_to_replace
21275        .end
21276        .cmp(&cursor_position, &buffer_snapshot)
21277        .is_lt()
21278    {
21279        range_to_replace.end = *cursor_position;
21280    }
21281
21282    CompletionEdit {
21283        new_text,
21284        replace_range: range_to_replace.to_offset(&buffer),
21285        snippet,
21286    }
21287}
21288
21289struct CompletionEdit {
21290    new_text: String,
21291    replace_range: Range<usize>,
21292    snippet: Option<Snippet>,
21293}
21294
21295fn insert_extra_newline_brackets(
21296    buffer: &MultiBufferSnapshot,
21297    range: Range<usize>,
21298    language: &language::LanguageScope,
21299) -> bool {
21300    let leading_whitespace_len = buffer
21301        .reversed_chars_at(range.start)
21302        .take_while(|c| c.is_whitespace() && *c != '\n')
21303        .map(|c| c.len_utf8())
21304        .sum::<usize>();
21305    let trailing_whitespace_len = buffer
21306        .chars_at(range.end)
21307        .take_while(|c| c.is_whitespace() && *c != '\n')
21308        .map(|c| c.len_utf8())
21309        .sum::<usize>();
21310    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21311
21312    language.brackets().any(|(pair, enabled)| {
21313        let pair_start = pair.start.trim_end();
21314        let pair_end = pair.end.trim_start();
21315
21316        enabled
21317            && pair.newline
21318            && buffer.contains_str_at(range.end, pair_end)
21319            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21320    })
21321}
21322
21323fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21324    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21325        [(buffer, range, _)] => (*buffer, range.clone()),
21326        _ => return false,
21327    };
21328    let pair = {
21329        let mut result: Option<BracketMatch> = None;
21330
21331        for pair in buffer
21332            .all_bracket_ranges(range.clone())
21333            .filter(move |pair| {
21334                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21335            })
21336        {
21337            let len = pair.close_range.end - pair.open_range.start;
21338
21339            if let Some(existing) = &result {
21340                let existing_len = existing.close_range.end - existing.open_range.start;
21341                if len > existing_len {
21342                    continue;
21343                }
21344            }
21345
21346            result = Some(pair);
21347        }
21348
21349        result
21350    };
21351    let Some(pair) = pair else {
21352        return false;
21353    };
21354    pair.newline_only
21355        && buffer
21356            .chars_for_range(pair.open_range.end..range.start)
21357            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21358            .all(|c| c.is_whitespace() && c != '\n')
21359}
21360
21361fn update_uncommitted_diff_for_buffer(
21362    editor: Entity<Editor>,
21363    project: &Entity<Project>,
21364    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21365    buffer: Entity<MultiBuffer>,
21366    cx: &mut App,
21367) -> Task<()> {
21368    let mut tasks = Vec::new();
21369    project.update(cx, |project, cx| {
21370        for buffer in buffers {
21371            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21372                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21373            }
21374        }
21375    });
21376    cx.spawn(async move |cx| {
21377        let diffs = future::join_all(tasks).await;
21378        if editor
21379            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21380            .unwrap_or(false)
21381        {
21382            return;
21383        }
21384
21385        buffer
21386            .update(cx, |buffer, cx| {
21387                for diff in diffs.into_iter().flatten() {
21388                    buffer.add_diff(diff, cx);
21389                }
21390            })
21391            .ok();
21392    })
21393}
21394
21395fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21396    let tab_size = tab_size.get() as usize;
21397    let mut width = offset;
21398
21399    for ch in text.chars() {
21400        width += if ch == '\t' {
21401            tab_size - (width % tab_size)
21402        } else {
21403            1
21404        };
21405    }
21406
21407    width - offset
21408}
21409
21410#[cfg(test)]
21411mod tests {
21412    use super::*;
21413
21414    #[test]
21415    fn test_string_size_with_expanded_tabs() {
21416        let nz = |val| NonZeroU32::new(val).unwrap();
21417        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21418        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21419        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21420        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21421        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21422        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21423        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21424        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21425    }
21426}
21427
21428/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21429struct WordBreakingTokenizer<'a> {
21430    input: &'a str,
21431}
21432
21433impl<'a> WordBreakingTokenizer<'a> {
21434    fn new(input: &'a str) -> Self {
21435        Self { input }
21436    }
21437}
21438
21439fn is_char_ideographic(ch: char) -> bool {
21440    use unicode_script::Script::*;
21441    use unicode_script::UnicodeScript;
21442    matches!(ch.script(), Han | Tangut | Yi)
21443}
21444
21445fn is_grapheme_ideographic(text: &str) -> bool {
21446    text.chars().any(is_char_ideographic)
21447}
21448
21449fn is_grapheme_whitespace(text: &str) -> bool {
21450    text.chars().any(|x| x.is_whitespace())
21451}
21452
21453fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21454    text.chars().next().map_or(false, |ch| {
21455        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
21456    })
21457}
21458
21459#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21460enum WordBreakToken<'a> {
21461    Word { token: &'a str, grapheme_len: usize },
21462    InlineWhitespace { token: &'a str, grapheme_len: usize },
21463    Newline,
21464}
21465
21466impl<'a> Iterator for WordBreakingTokenizer<'a> {
21467    /// Yields a span, the count of graphemes in the token, and whether it was
21468    /// whitespace. Note that it also breaks at word boundaries.
21469    type Item = WordBreakToken<'a>;
21470
21471    fn next(&mut self) -> Option<Self::Item> {
21472        use unicode_segmentation::UnicodeSegmentation;
21473        if self.input.is_empty() {
21474            return None;
21475        }
21476
21477        let mut iter = self.input.graphemes(true).peekable();
21478        let mut offset = 0;
21479        let mut grapheme_len = 0;
21480        if let Some(first_grapheme) = iter.next() {
21481            let is_newline = first_grapheme == "\n";
21482            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21483            offset += first_grapheme.len();
21484            grapheme_len += 1;
21485            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21486                if let Some(grapheme) = iter.peek().copied() {
21487                    if should_stay_with_preceding_ideograph(grapheme) {
21488                        offset += grapheme.len();
21489                        grapheme_len += 1;
21490                    }
21491                }
21492            } else {
21493                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21494                let mut next_word_bound = words.peek().copied();
21495                if next_word_bound.map_or(false, |(i, _)| i == 0) {
21496                    next_word_bound = words.next();
21497                }
21498                while let Some(grapheme) = iter.peek().copied() {
21499                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
21500                        break;
21501                    };
21502                    if is_grapheme_whitespace(grapheme) != is_whitespace
21503                        || (grapheme == "\n") != is_newline
21504                    {
21505                        break;
21506                    };
21507                    offset += grapheme.len();
21508                    grapheme_len += 1;
21509                    iter.next();
21510                }
21511            }
21512            let token = &self.input[..offset];
21513            self.input = &self.input[offset..];
21514            if token == "\n" {
21515                Some(WordBreakToken::Newline)
21516            } else if is_whitespace {
21517                Some(WordBreakToken::InlineWhitespace {
21518                    token,
21519                    grapheme_len,
21520                })
21521            } else {
21522                Some(WordBreakToken::Word {
21523                    token,
21524                    grapheme_len,
21525                })
21526            }
21527        } else {
21528            None
21529        }
21530    }
21531}
21532
21533#[test]
21534fn test_word_breaking_tokenizer() {
21535    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21536        ("", &[]),
21537        ("  ", &[whitespace("  ", 2)]),
21538        ("Ʒ", &[word("Ʒ", 1)]),
21539        ("Ǽ", &[word("Ǽ", 1)]),
21540        ("", &[word("", 1)]),
21541        ("⋑⋑", &[word("⋑⋑", 2)]),
21542        (
21543            "原理,进而",
21544            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21545        ),
21546        (
21547            "hello world",
21548            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21549        ),
21550        (
21551            "hello, world",
21552            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21553        ),
21554        (
21555            "  hello world",
21556            &[
21557                whitespace("  ", 2),
21558                word("hello", 5),
21559                whitespace(" ", 1),
21560                word("world", 5),
21561            ],
21562        ),
21563        (
21564            "这是什么 \n 钢笔",
21565            &[
21566                word("", 1),
21567                word("", 1),
21568                word("", 1),
21569                word("", 1),
21570                whitespace(" ", 1),
21571                newline(),
21572                whitespace(" ", 1),
21573                word("", 1),
21574                word("", 1),
21575            ],
21576        ),
21577        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21578    ];
21579
21580    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21581        WordBreakToken::Word {
21582            token,
21583            grapheme_len,
21584        }
21585    }
21586
21587    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21588        WordBreakToken::InlineWhitespace {
21589            token,
21590            grapheme_len,
21591        }
21592    }
21593
21594    fn newline() -> WordBreakToken<'static> {
21595        WordBreakToken::Newline
21596    }
21597
21598    for (input, result) in tests {
21599        assert_eq!(
21600            WordBreakingTokenizer::new(input)
21601                .collect::<Vec<_>>()
21602                .as_slice(),
21603            *result,
21604        );
21605    }
21606}
21607
21608fn wrap_with_prefix(
21609    first_line_prefix: String,
21610    subsequent_lines_prefix: String,
21611    unwrapped_text: String,
21612    wrap_column: usize,
21613    tab_size: NonZeroU32,
21614    preserve_existing_whitespace: bool,
21615) -> String {
21616    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21617    let subsequent_lines_prefix_len =
21618        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21619    let mut wrapped_text = String::new();
21620    let mut current_line = first_line_prefix.clone();
21621    let mut is_first_line = true;
21622
21623    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21624    let mut current_line_len = first_line_prefix_len;
21625    let mut in_whitespace = false;
21626    for token in tokenizer {
21627        let have_preceding_whitespace = in_whitespace;
21628        match token {
21629            WordBreakToken::Word {
21630                token,
21631                grapheme_len,
21632            } => {
21633                in_whitespace = false;
21634                let current_prefix_len = if is_first_line {
21635                    first_line_prefix_len
21636                } else {
21637                    subsequent_lines_prefix_len
21638                };
21639                if current_line_len + grapheme_len > wrap_column
21640                    && current_line_len != current_prefix_len
21641                {
21642                    wrapped_text.push_str(current_line.trim_end());
21643                    wrapped_text.push('\n');
21644                    is_first_line = false;
21645                    current_line = subsequent_lines_prefix.clone();
21646                    current_line_len = subsequent_lines_prefix_len;
21647                }
21648                current_line.push_str(token);
21649                current_line_len += grapheme_len;
21650            }
21651            WordBreakToken::InlineWhitespace {
21652                mut token,
21653                mut grapheme_len,
21654            } => {
21655                in_whitespace = true;
21656                if have_preceding_whitespace && !preserve_existing_whitespace {
21657                    continue;
21658                }
21659                if !preserve_existing_whitespace {
21660                    token = " ";
21661                    grapheme_len = 1;
21662                }
21663                let current_prefix_len = if is_first_line {
21664                    first_line_prefix_len
21665                } else {
21666                    subsequent_lines_prefix_len
21667                };
21668                if current_line_len + grapheme_len > wrap_column {
21669                    wrapped_text.push_str(current_line.trim_end());
21670                    wrapped_text.push('\n');
21671                    is_first_line = false;
21672                    current_line = subsequent_lines_prefix.clone();
21673                    current_line_len = subsequent_lines_prefix_len;
21674                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21675                    current_line.push_str(token);
21676                    current_line_len += grapheme_len;
21677                }
21678            }
21679            WordBreakToken::Newline => {
21680                in_whitespace = true;
21681                let current_prefix_len = if is_first_line {
21682                    first_line_prefix_len
21683                } else {
21684                    subsequent_lines_prefix_len
21685                };
21686                if preserve_existing_whitespace {
21687                    wrapped_text.push_str(current_line.trim_end());
21688                    wrapped_text.push('\n');
21689                    is_first_line = false;
21690                    current_line = subsequent_lines_prefix.clone();
21691                    current_line_len = subsequent_lines_prefix_len;
21692                } else if have_preceding_whitespace {
21693                    continue;
21694                } else if current_line_len + 1 > wrap_column
21695                    && current_line_len != current_prefix_len
21696                {
21697                    wrapped_text.push_str(current_line.trim_end());
21698                    wrapped_text.push('\n');
21699                    is_first_line = false;
21700                    current_line = subsequent_lines_prefix.clone();
21701                    current_line_len = subsequent_lines_prefix_len;
21702                } else if current_line_len != current_prefix_len {
21703                    current_line.push(' ');
21704                    current_line_len += 1;
21705                }
21706            }
21707        }
21708    }
21709
21710    if !current_line.is_empty() {
21711        wrapped_text.push_str(&current_line);
21712    }
21713    wrapped_text
21714}
21715
21716#[test]
21717fn test_wrap_with_prefix() {
21718    assert_eq!(
21719        wrap_with_prefix(
21720            "# ".to_string(),
21721            "# ".to_string(),
21722            "abcdefg".to_string(),
21723            4,
21724            NonZeroU32::new(4).unwrap(),
21725            false,
21726        ),
21727        "# abcdefg"
21728    );
21729    assert_eq!(
21730        wrap_with_prefix(
21731            "".to_string(),
21732            "".to_string(),
21733            "\thello world".to_string(),
21734            8,
21735            NonZeroU32::new(4).unwrap(),
21736            false,
21737        ),
21738        "hello\nworld"
21739    );
21740    assert_eq!(
21741        wrap_with_prefix(
21742            "// ".to_string(),
21743            "// ".to_string(),
21744            "xx \nyy zz aa bb cc".to_string(),
21745            12,
21746            NonZeroU32::new(4).unwrap(),
21747            false,
21748        ),
21749        "// xx yy zz\n// aa bb cc"
21750    );
21751    assert_eq!(
21752        wrap_with_prefix(
21753            String::new(),
21754            String::new(),
21755            "这是什么 \n 钢笔".to_string(),
21756            3,
21757            NonZeroU32::new(4).unwrap(),
21758            false,
21759        ),
21760        "这是什\n么 钢\n"
21761    );
21762}
21763
21764pub trait CollaborationHub {
21765    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21766    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21767    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21768}
21769
21770impl CollaborationHub for Entity<Project> {
21771    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21772        self.read(cx).collaborators()
21773    }
21774
21775    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21776        self.read(cx).user_store().read(cx).participant_indices()
21777    }
21778
21779    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21780        let this = self.read(cx);
21781        let user_ids = this.collaborators().values().map(|c| c.user_id);
21782        this.user_store().read(cx).participant_names(user_ids, cx)
21783    }
21784}
21785
21786pub trait SemanticsProvider {
21787    fn hover(
21788        &self,
21789        buffer: &Entity<Buffer>,
21790        position: text::Anchor,
21791        cx: &mut App,
21792    ) -> Option<Task<Vec<project::Hover>>>;
21793
21794    fn inline_values(
21795        &self,
21796        buffer_handle: Entity<Buffer>,
21797        range: Range<text::Anchor>,
21798        cx: &mut App,
21799    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21800
21801    fn inlay_hints(
21802        &self,
21803        buffer_handle: Entity<Buffer>,
21804        range: Range<text::Anchor>,
21805        cx: &mut App,
21806    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21807
21808    fn resolve_inlay_hint(
21809        &self,
21810        hint: InlayHint,
21811        buffer_handle: Entity<Buffer>,
21812        server_id: LanguageServerId,
21813        cx: &mut App,
21814    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21815
21816    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21817
21818    fn document_highlights(
21819        &self,
21820        buffer: &Entity<Buffer>,
21821        position: text::Anchor,
21822        cx: &mut App,
21823    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21824
21825    fn definitions(
21826        &self,
21827        buffer: &Entity<Buffer>,
21828        position: text::Anchor,
21829        kind: GotoDefinitionKind,
21830        cx: &mut App,
21831    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21832
21833    fn range_for_rename(
21834        &self,
21835        buffer: &Entity<Buffer>,
21836        position: text::Anchor,
21837        cx: &mut App,
21838    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21839
21840    fn perform_rename(
21841        &self,
21842        buffer: &Entity<Buffer>,
21843        position: text::Anchor,
21844        new_name: String,
21845        cx: &mut App,
21846    ) -> Option<Task<Result<ProjectTransaction>>>;
21847}
21848
21849pub trait CompletionProvider {
21850    fn completions(
21851        &self,
21852        excerpt_id: ExcerptId,
21853        buffer: &Entity<Buffer>,
21854        buffer_position: text::Anchor,
21855        trigger: CompletionContext,
21856        window: &mut Window,
21857        cx: &mut Context<Editor>,
21858    ) -> Task<Result<Vec<CompletionResponse>>>;
21859
21860    fn resolve_completions(
21861        &self,
21862        _buffer: Entity<Buffer>,
21863        _completion_indices: Vec<usize>,
21864        _completions: Rc<RefCell<Box<[Completion]>>>,
21865        _cx: &mut Context<Editor>,
21866    ) -> Task<Result<bool>> {
21867        Task::ready(Ok(false))
21868    }
21869
21870    fn apply_additional_edits_for_completion(
21871        &self,
21872        _buffer: Entity<Buffer>,
21873        _completions: Rc<RefCell<Box<[Completion]>>>,
21874        _completion_index: usize,
21875        _push_to_history: bool,
21876        _cx: &mut Context<Editor>,
21877    ) -> Task<Result<Option<language::Transaction>>> {
21878        Task::ready(Ok(None))
21879    }
21880
21881    fn is_completion_trigger(
21882        &self,
21883        buffer: &Entity<Buffer>,
21884        position: language::Anchor,
21885        text: &str,
21886        trigger_in_words: bool,
21887        menu_is_open: bool,
21888        cx: &mut Context<Editor>,
21889    ) -> bool;
21890
21891    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21892
21893    fn sort_completions(&self) -> bool {
21894        true
21895    }
21896
21897    fn filter_completions(&self) -> bool {
21898        true
21899    }
21900}
21901
21902pub trait CodeActionProvider {
21903    fn id(&self) -> Arc<str>;
21904
21905    fn code_actions(
21906        &self,
21907        buffer: &Entity<Buffer>,
21908        range: Range<text::Anchor>,
21909        window: &mut Window,
21910        cx: &mut App,
21911    ) -> Task<Result<Vec<CodeAction>>>;
21912
21913    fn apply_code_action(
21914        &self,
21915        buffer_handle: Entity<Buffer>,
21916        action: CodeAction,
21917        excerpt_id: ExcerptId,
21918        push_to_history: bool,
21919        window: &mut Window,
21920        cx: &mut App,
21921    ) -> Task<Result<ProjectTransaction>>;
21922}
21923
21924impl CodeActionProvider for Entity<Project> {
21925    fn id(&self) -> Arc<str> {
21926        "project".into()
21927    }
21928
21929    fn code_actions(
21930        &self,
21931        buffer: &Entity<Buffer>,
21932        range: Range<text::Anchor>,
21933        _window: &mut Window,
21934        cx: &mut App,
21935    ) -> Task<Result<Vec<CodeAction>>> {
21936        self.update(cx, |project, cx| {
21937            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
21938            let code_actions = project.code_actions(buffer, range, None, cx);
21939            cx.background_spawn(async move {
21940                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
21941                Ok(code_lens_actions
21942                    .context("code lens fetch")?
21943                    .into_iter()
21944                    .chain(code_actions.context("code action fetch")?)
21945                    .collect())
21946            })
21947        })
21948    }
21949
21950    fn apply_code_action(
21951        &self,
21952        buffer_handle: Entity<Buffer>,
21953        action: CodeAction,
21954        _excerpt_id: ExcerptId,
21955        push_to_history: bool,
21956        _window: &mut Window,
21957        cx: &mut App,
21958    ) -> Task<Result<ProjectTransaction>> {
21959        self.update(cx, |project, cx| {
21960            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21961        })
21962    }
21963}
21964
21965fn snippet_completions(
21966    project: &Project,
21967    buffer: &Entity<Buffer>,
21968    buffer_position: text::Anchor,
21969    cx: &mut App,
21970) -> Task<Result<CompletionResponse>> {
21971    let languages = buffer.read(cx).languages_at(buffer_position);
21972    let snippet_store = project.snippets().read(cx);
21973
21974    let scopes: Vec<_> = languages
21975        .iter()
21976        .filter_map(|language| {
21977            let language_name = language.lsp_id();
21978            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21979
21980            if snippets.is_empty() {
21981                None
21982            } else {
21983                Some((language.default_scope(), snippets))
21984            }
21985        })
21986        .collect();
21987
21988    if scopes.is_empty() {
21989        return Task::ready(Ok(CompletionResponse {
21990            completions: vec![],
21991            is_incomplete: false,
21992        }));
21993    }
21994
21995    let snapshot = buffer.read(cx).text_snapshot();
21996    let chars: String = snapshot
21997        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21998        .collect();
21999    let executor = cx.background_executor().clone();
22000
22001    cx.background_spawn(async move {
22002        let mut is_incomplete = false;
22003        let mut completions: Vec<Completion> = Vec::new();
22004        for (scope, snippets) in scopes.into_iter() {
22005            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22006            let mut last_word = chars
22007                .chars()
22008                .take_while(|c| classifier.is_word(*c))
22009                .collect::<String>();
22010            last_word = last_word.chars().rev().collect();
22011
22012            if last_word.is_empty() {
22013                return Ok(CompletionResponse {
22014                    completions: vec![],
22015                    is_incomplete: true,
22016                });
22017            }
22018
22019            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22020            let to_lsp = |point: &text::Anchor| {
22021                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22022                point_to_lsp(end)
22023            };
22024            let lsp_end = to_lsp(&buffer_position);
22025
22026            let candidates = snippets
22027                .iter()
22028                .enumerate()
22029                .flat_map(|(ix, snippet)| {
22030                    snippet
22031                        .prefix
22032                        .iter()
22033                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
22034                })
22035                .collect::<Vec<StringMatchCandidate>>();
22036
22037            const MAX_RESULTS: usize = 100;
22038            let mut matches = fuzzy::match_strings(
22039                &candidates,
22040                &last_word,
22041                last_word.chars().any(|c| c.is_uppercase()),
22042                true,
22043                MAX_RESULTS,
22044                &Default::default(),
22045                executor.clone(),
22046            )
22047            .await;
22048
22049            if matches.len() >= MAX_RESULTS {
22050                is_incomplete = true;
22051            }
22052
22053            // Remove all candidates where the query's start does not match the start of any word in the candidate
22054            if let Some(query_start) = last_word.chars().next() {
22055                matches.retain(|string_match| {
22056                    split_words(&string_match.string).any(|word| {
22057                        // Check that the first codepoint of the word as lowercase matches the first
22058                        // codepoint of the query as lowercase
22059                        word.chars()
22060                            .flat_map(|codepoint| codepoint.to_lowercase())
22061                            .zip(query_start.to_lowercase())
22062                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22063                    })
22064                });
22065            }
22066
22067            let matched_strings = matches
22068                .into_iter()
22069                .map(|m| m.string)
22070                .collect::<HashSet<_>>();
22071
22072            completions.extend(snippets.iter().filter_map(|snippet| {
22073                let matching_prefix = snippet
22074                    .prefix
22075                    .iter()
22076                    .find(|prefix| matched_strings.contains(*prefix))?;
22077                let start = as_offset - last_word.len();
22078                let start = snapshot.anchor_before(start);
22079                let range = start..buffer_position;
22080                let lsp_start = to_lsp(&start);
22081                let lsp_range = lsp::Range {
22082                    start: lsp_start,
22083                    end: lsp_end,
22084                };
22085                Some(Completion {
22086                    replace_range: range,
22087                    new_text: snippet.body.clone(),
22088                    source: CompletionSource::Lsp {
22089                        insert_range: None,
22090                        server_id: LanguageServerId(usize::MAX),
22091                        resolved: true,
22092                        lsp_completion: Box::new(lsp::CompletionItem {
22093                            label: snippet.prefix.first().unwrap().clone(),
22094                            kind: Some(CompletionItemKind::SNIPPET),
22095                            label_details: snippet.description.as_ref().map(|description| {
22096                                lsp::CompletionItemLabelDetails {
22097                                    detail: Some(description.clone()),
22098                                    description: None,
22099                                }
22100                            }),
22101                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22102                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22103                                lsp::InsertReplaceEdit {
22104                                    new_text: snippet.body.clone(),
22105                                    insert: lsp_range,
22106                                    replace: lsp_range,
22107                                },
22108                            )),
22109                            filter_text: Some(snippet.body.clone()),
22110                            sort_text: Some(char::MAX.to_string()),
22111                            ..lsp::CompletionItem::default()
22112                        }),
22113                        lsp_defaults: None,
22114                    },
22115                    label: CodeLabel {
22116                        text: matching_prefix.clone(),
22117                        runs: Vec::new(),
22118                        filter_range: 0..matching_prefix.len(),
22119                    },
22120                    icon_path: None,
22121                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22122                        single_line: snippet.name.clone().into(),
22123                        plain_text: snippet
22124                            .description
22125                            .clone()
22126                            .map(|description| description.into()),
22127                    }),
22128                    insert_text_mode: None,
22129                    confirm: None,
22130                })
22131            }))
22132        }
22133
22134        Ok(CompletionResponse {
22135            completions,
22136            is_incomplete,
22137        })
22138    })
22139}
22140
22141impl CompletionProvider for Entity<Project> {
22142    fn completions(
22143        &self,
22144        _excerpt_id: ExcerptId,
22145        buffer: &Entity<Buffer>,
22146        buffer_position: text::Anchor,
22147        options: CompletionContext,
22148        _window: &mut Window,
22149        cx: &mut Context<Editor>,
22150    ) -> Task<Result<Vec<CompletionResponse>>> {
22151        self.update(cx, |project, cx| {
22152            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22153            let project_completions = project.completions(buffer, buffer_position, options, cx);
22154            cx.background_spawn(async move {
22155                let mut responses = project_completions.await?;
22156                let snippets = snippets.await?;
22157                if !snippets.completions.is_empty() {
22158                    responses.push(snippets);
22159                }
22160                Ok(responses)
22161            })
22162        })
22163    }
22164
22165    fn resolve_completions(
22166        &self,
22167        buffer: Entity<Buffer>,
22168        completion_indices: Vec<usize>,
22169        completions: Rc<RefCell<Box<[Completion]>>>,
22170        cx: &mut Context<Editor>,
22171    ) -> Task<Result<bool>> {
22172        self.update(cx, |project, cx| {
22173            project.lsp_store().update(cx, |lsp_store, cx| {
22174                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22175            })
22176        })
22177    }
22178
22179    fn apply_additional_edits_for_completion(
22180        &self,
22181        buffer: Entity<Buffer>,
22182        completions: Rc<RefCell<Box<[Completion]>>>,
22183        completion_index: usize,
22184        push_to_history: bool,
22185        cx: &mut Context<Editor>,
22186    ) -> Task<Result<Option<language::Transaction>>> {
22187        self.update(cx, |project, cx| {
22188            project.lsp_store().update(cx, |lsp_store, cx| {
22189                lsp_store.apply_additional_edits_for_completion(
22190                    buffer,
22191                    completions,
22192                    completion_index,
22193                    push_to_history,
22194                    cx,
22195                )
22196            })
22197        })
22198    }
22199
22200    fn is_completion_trigger(
22201        &self,
22202        buffer: &Entity<Buffer>,
22203        position: language::Anchor,
22204        text: &str,
22205        trigger_in_words: bool,
22206        menu_is_open: bool,
22207        cx: &mut Context<Editor>,
22208    ) -> bool {
22209        let mut chars = text.chars();
22210        let char = if let Some(char) = chars.next() {
22211            char
22212        } else {
22213            return false;
22214        };
22215        if chars.next().is_some() {
22216            return false;
22217        }
22218
22219        let buffer = buffer.read(cx);
22220        let snapshot = buffer.snapshot();
22221        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22222            return false;
22223        }
22224        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22225        if trigger_in_words && classifier.is_word(char) {
22226            return true;
22227        }
22228
22229        buffer.completion_triggers().contains(text)
22230    }
22231}
22232
22233impl SemanticsProvider for Entity<Project> {
22234    fn hover(
22235        &self,
22236        buffer: &Entity<Buffer>,
22237        position: text::Anchor,
22238        cx: &mut App,
22239    ) -> Option<Task<Vec<project::Hover>>> {
22240        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22241    }
22242
22243    fn document_highlights(
22244        &self,
22245        buffer: &Entity<Buffer>,
22246        position: text::Anchor,
22247        cx: &mut App,
22248    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22249        Some(self.update(cx, |project, cx| {
22250            project.document_highlights(buffer, position, cx)
22251        }))
22252    }
22253
22254    fn definitions(
22255        &self,
22256        buffer: &Entity<Buffer>,
22257        position: text::Anchor,
22258        kind: GotoDefinitionKind,
22259        cx: &mut App,
22260    ) -> Option<Task<Result<Vec<LocationLink>>>> {
22261        Some(self.update(cx, |project, cx| match kind {
22262            GotoDefinitionKind::Symbol => project.definitions(&buffer, position, cx),
22263            GotoDefinitionKind::Declaration => project.declarations(&buffer, position, cx),
22264            GotoDefinitionKind::Type => project.type_definitions(&buffer, position, cx),
22265            GotoDefinitionKind::Implementation => project.implementations(&buffer, position, cx),
22266        }))
22267    }
22268
22269    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22270        self.update(cx, |project, cx| {
22271            if project
22272                .active_debug_session(cx)
22273                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22274            {
22275                return true;
22276            }
22277
22278            buffer.update(cx, |buffer, cx| {
22279                project.any_language_server_supports_inlay_hints(buffer, cx)
22280            })
22281        })
22282    }
22283
22284    fn inline_values(
22285        &self,
22286        buffer_handle: Entity<Buffer>,
22287        range: Range<text::Anchor>,
22288        cx: &mut App,
22289    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22290        self.update(cx, |project, cx| {
22291            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22292
22293            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22294        })
22295    }
22296
22297    fn inlay_hints(
22298        &self,
22299        buffer_handle: Entity<Buffer>,
22300        range: Range<text::Anchor>,
22301        cx: &mut App,
22302    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22303        Some(self.update(cx, |project, cx| {
22304            project.inlay_hints(buffer_handle, range, cx)
22305        }))
22306    }
22307
22308    fn resolve_inlay_hint(
22309        &self,
22310        hint: InlayHint,
22311        buffer_handle: Entity<Buffer>,
22312        server_id: LanguageServerId,
22313        cx: &mut App,
22314    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22315        Some(self.update(cx, |project, cx| {
22316            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22317        }))
22318    }
22319
22320    fn range_for_rename(
22321        &self,
22322        buffer: &Entity<Buffer>,
22323        position: text::Anchor,
22324        cx: &mut App,
22325    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22326        Some(self.update(cx, |project, cx| {
22327            let buffer = buffer.clone();
22328            let task = project.prepare_rename(buffer.clone(), position, cx);
22329            cx.spawn(async move |_, cx| {
22330                Ok(match task.await? {
22331                    PrepareRenameResponse::Success(range) => Some(range),
22332                    PrepareRenameResponse::InvalidPosition => None,
22333                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22334                        // Fallback on using TreeSitter info to determine identifier range
22335                        buffer.read_with(cx, |buffer, _| {
22336                            let snapshot = buffer.snapshot();
22337                            let (range, kind) = snapshot.surrounding_word(position, false);
22338                            if kind != Some(CharKind::Word) {
22339                                return None;
22340                            }
22341                            Some(
22342                                snapshot.anchor_before(range.start)
22343                                    ..snapshot.anchor_after(range.end),
22344                            )
22345                        })?
22346                    }
22347                })
22348            })
22349        }))
22350    }
22351
22352    fn perform_rename(
22353        &self,
22354        buffer: &Entity<Buffer>,
22355        position: text::Anchor,
22356        new_name: String,
22357        cx: &mut App,
22358    ) -> Option<Task<Result<ProjectTransaction>>> {
22359        Some(self.update(cx, |project, cx| {
22360            project.perform_rename(buffer.clone(), position, new_name, cx)
22361        }))
22362    }
22363}
22364
22365fn inlay_hint_settings(
22366    location: Anchor,
22367    snapshot: &MultiBufferSnapshot,
22368    cx: &mut Context<Editor>,
22369) -> InlayHintSettings {
22370    let file = snapshot.file_at(location);
22371    let language = snapshot.language_at(location).map(|l| l.name());
22372    language_settings(language, file, cx).inlay_hints
22373}
22374
22375fn consume_contiguous_rows(
22376    contiguous_row_selections: &mut Vec<Selection<Point>>,
22377    selection: &Selection<Point>,
22378    display_map: &DisplaySnapshot,
22379    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22380) -> (MultiBufferRow, MultiBufferRow) {
22381    contiguous_row_selections.push(selection.clone());
22382    let start_row = starting_row(selection, display_map);
22383    let mut end_row = ending_row(selection, display_map);
22384
22385    while let Some(next_selection) = selections.peek() {
22386        if next_selection.start.row <= end_row.0 {
22387            end_row = ending_row(next_selection, display_map);
22388            contiguous_row_selections.push(selections.next().unwrap().clone());
22389        } else {
22390            break;
22391        }
22392    }
22393    (start_row, end_row)
22394}
22395
22396fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22397    if selection.start.column > 0 {
22398        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22399    } else {
22400        MultiBufferRow(selection.start.row)
22401    }
22402}
22403
22404fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22405    if next_selection.end.column > 0 || next_selection.is_empty() {
22406        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22407    } else {
22408        MultiBufferRow(next_selection.end.row)
22409    }
22410}
22411
22412impl EditorSnapshot {
22413    pub fn remote_selections_in_range<'a>(
22414        &'a self,
22415        range: &'a Range<Anchor>,
22416        collaboration_hub: &dyn CollaborationHub,
22417        cx: &'a App,
22418    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22419        let participant_names = collaboration_hub.user_names(cx);
22420        let participant_indices = collaboration_hub.user_participant_indices(cx);
22421        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22422        let collaborators_by_replica_id = collaborators_by_peer_id
22423            .values()
22424            .map(|collaborator| (collaborator.replica_id, collaborator))
22425            .collect::<HashMap<_, _>>();
22426        self.buffer_snapshot
22427            .selections_in_range(range, false)
22428            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22429                if replica_id == AGENT_REPLICA_ID {
22430                    Some(RemoteSelection {
22431                        replica_id,
22432                        selection,
22433                        cursor_shape,
22434                        line_mode,
22435                        collaborator_id: CollaboratorId::Agent,
22436                        user_name: Some("Agent".into()),
22437                        color: cx.theme().players().agent(),
22438                    })
22439                } else {
22440                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22441                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22442                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22443                    Some(RemoteSelection {
22444                        replica_id,
22445                        selection,
22446                        cursor_shape,
22447                        line_mode,
22448                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22449                        user_name,
22450                        color: if let Some(index) = participant_index {
22451                            cx.theme().players().color_for_participant(index.0)
22452                        } else {
22453                            cx.theme().players().absent()
22454                        },
22455                    })
22456                }
22457            })
22458    }
22459
22460    pub fn hunks_for_ranges(
22461        &self,
22462        ranges: impl IntoIterator<Item = Range<Point>>,
22463    ) -> Vec<MultiBufferDiffHunk> {
22464        let mut hunks = Vec::new();
22465        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22466            HashMap::default();
22467        for query_range in ranges {
22468            let query_rows =
22469                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22470            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22471                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22472            ) {
22473                // Include deleted hunks that are adjacent to the query range, because
22474                // otherwise they would be missed.
22475                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22476                if hunk.status().is_deleted() {
22477                    intersects_range |= hunk.row_range.start == query_rows.end;
22478                    intersects_range |= hunk.row_range.end == query_rows.start;
22479                }
22480                if intersects_range {
22481                    if !processed_buffer_rows
22482                        .entry(hunk.buffer_id)
22483                        .or_default()
22484                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22485                    {
22486                        continue;
22487                    }
22488                    hunks.push(hunk);
22489                }
22490            }
22491        }
22492
22493        hunks
22494    }
22495
22496    fn display_diff_hunks_for_rows<'a>(
22497        &'a self,
22498        display_rows: Range<DisplayRow>,
22499        folded_buffers: &'a HashSet<BufferId>,
22500    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22501        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22502        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22503
22504        self.buffer_snapshot
22505            .diff_hunks_in_range(buffer_start..buffer_end)
22506            .filter_map(|hunk| {
22507                if folded_buffers.contains(&hunk.buffer_id) {
22508                    return None;
22509                }
22510
22511                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22512                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22513
22514                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22515                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22516
22517                let display_hunk = if hunk_display_start.column() != 0 {
22518                    DisplayDiffHunk::Folded {
22519                        display_row: hunk_display_start.row(),
22520                    }
22521                } else {
22522                    let mut end_row = hunk_display_end.row();
22523                    if hunk_display_end.column() > 0 {
22524                        end_row.0 += 1;
22525                    }
22526                    let is_created_file = hunk.is_created_file();
22527                    DisplayDiffHunk::Unfolded {
22528                        status: hunk.status(),
22529                        diff_base_byte_range: hunk.diff_base_byte_range,
22530                        display_row_range: hunk_display_start.row()..end_row,
22531                        multi_buffer_range: Anchor::range_in_buffer(
22532                            hunk.excerpt_id,
22533                            hunk.buffer_id,
22534                            hunk.buffer_range,
22535                        ),
22536                        is_created_file,
22537                    }
22538                };
22539
22540                Some(display_hunk)
22541            })
22542    }
22543
22544    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22545        self.display_snapshot.buffer_snapshot.language_at(position)
22546    }
22547
22548    pub fn is_focused(&self) -> bool {
22549        self.is_focused
22550    }
22551
22552    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22553        self.placeholder_text.as_ref()
22554    }
22555
22556    pub fn scroll_position(&self) -> gpui::Point<f32> {
22557        self.scroll_anchor.scroll_position(&self.display_snapshot)
22558    }
22559
22560    fn gutter_dimensions(
22561        &self,
22562        font_id: FontId,
22563        font_size: Pixels,
22564        max_line_number_width: Pixels,
22565        cx: &App,
22566    ) -> Option<GutterDimensions> {
22567        if !self.show_gutter {
22568            return None;
22569        }
22570
22571        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22572        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22573
22574        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22575            matches!(
22576                ProjectSettings::get_global(cx).git.git_gutter,
22577                Some(GitGutterSetting::TrackedFiles)
22578            )
22579        });
22580        let gutter_settings = EditorSettings::get_global(cx).gutter;
22581        let show_line_numbers = self
22582            .show_line_numbers
22583            .unwrap_or(gutter_settings.line_numbers);
22584        let line_gutter_width = if show_line_numbers {
22585            // Avoid flicker-like gutter resizes when the line number gains another digit by
22586            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22587            let min_width_for_number_on_gutter =
22588                ch_advance * gutter_settings.min_line_number_digits as f32;
22589            max_line_number_width.max(min_width_for_number_on_gutter)
22590        } else {
22591            0.0.into()
22592        };
22593
22594        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22595        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22596
22597        let git_blame_entries_width =
22598            self.git_blame_gutter_max_author_length
22599                .map(|max_author_length| {
22600                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22601                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22602
22603                    /// The number of characters to dedicate to gaps and margins.
22604                    const SPACING_WIDTH: usize = 4;
22605
22606                    let max_char_count = max_author_length.min(renderer.max_author_length())
22607                        + ::git::SHORT_SHA_LENGTH
22608                        + MAX_RELATIVE_TIMESTAMP.len()
22609                        + SPACING_WIDTH;
22610
22611                    ch_advance * max_char_count
22612                });
22613
22614        let is_singleton = self.buffer_snapshot.is_singleton();
22615
22616        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22617        left_padding += if !is_singleton {
22618            ch_width * 4.0
22619        } else if show_runnables || show_breakpoints {
22620            ch_width * 3.0
22621        } else if show_git_gutter && show_line_numbers {
22622            ch_width * 2.0
22623        } else if show_git_gutter || show_line_numbers {
22624            ch_width
22625        } else {
22626            px(0.)
22627        };
22628
22629        let shows_folds = is_singleton && gutter_settings.folds;
22630
22631        let right_padding = if shows_folds && show_line_numbers {
22632            ch_width * 4.0
22633        } else if shows_folds || (!is_singleton && show_line_numbers) {
22634            ch_width * 3.0
22635        } else if show_line_numbers {
22636            ch_width
22637        } else {
22638            px(0.)
22639        };
22640
22641        Some(GutterDimensions {
22642            left_padding,
22643            right_padding,
22644            width: line_gutter_width + left_padding + right_padding,
22645            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22646            git_blame_entries_width,
22647        })
22648    }
22649
22650    pub fn render_crease_toggle(
22651        &self,
22652        buffer_row: MultiBufferRow,
22653        row_contains_cursor: bool,
22654        editor: Entity<Editor>,
22655        window: &mut Window,
22656        cx: &mut App,
22657    ) -> Option<AnyElement> {
22658        let folded = self.is_line_folded(buffer_row);
22659        let mut is_foldable = false;
22660
22661        if let Some(crease) = self
22662            .crease_snapshot
22663            .query_row(buffer_row, &self.buffer_snapshot)
22664        {
22665            is_foldable = true;
22666            match crease {
22667                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22668                    if let Some(render_toggle) = render_toggle {
22669                        let toggle_callback =
22670                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22671                                if folded {
22672                                    editor.update(cx, |editor, cx| {
22673                                        editor.fold_at(buffer_row, window, cx)
22674                                    });
22675                                } else {
22676                                    editor.update(cx, |editor, cx| {
22677                                        editor.unfold_at(buffer_row, window, cx)
22678                                    });
22679                                }
22680                            });
22681                        return Some((render_toggle)(
22682                            buffer_row,
22683                            folded,
22684                            toggle_callback,
22685                            window,
22686                            cx,
22687                        ));
22688                    }
22689                }
22690            }
22691        }
22692
22693        is_foldable |= self.starts_indent(buffer_row);
22694
22695        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22696            Some(
22697                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22698                    .toggle_state(folded)
22699                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22700                        if folded {
22701                            this.unfold_at(buffer_row, window, cx);
22702                        } else {
22703                            this.fold_at(buffer_row, window, cx);
22704                        }
22705                    }))
22706                    .into_any_element(),
22707            )
22708        } else {
22709            None
22710        }
22711    }
22712
22713    pub fn render_crease_trailer(
22714        &self,
22715        buffer_row: MultiBufferRow,
22716        window: &mut Window,
22717        cx: &mut App,
22718    ) -> Option<AnyElement> {
22719        let folded = self.is_line_folded(buffer_row);
22720        if let Crease::Inline { render_trailer, .. } = self
22721            .crease_snapshot
22722            .query_row(buffer_row, &self.buffer_snapshot)?
22723        {
22724            let render_trailer = render_trailer.as_ref()?;
22725            Some(render_trailer(buffer_row, folded, window, cx))
22726        } else {
22727            None
22728        }
22729    }
22730}
22731
22732impl Deref for EditorSnapshot {
22733    type Target = DisplaySnapshot;
22734
22735    fn deref(&self) -> &Self::Target {
22736        &self.display_snapshot
22737    }
22738}
22739
22740#[derive(Clone, Debug, PartialEq, Eq)]
22741pub enum EditorEvent {
22742    InputIgnored {
22743        text: Arc<str>,
22744    },
22745    InputHandled {
22746        utf16_range_to_replace: Option<Range<isize>>,
22747        text: Arc<str>,
22748    },
22749    ExcerptsAdded {
22750        buffer: Entity<Buffer>,
22751        predecessor: ExcerptId,
22752        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22753    },
22754    ExcerptsRemoved {
22755        ids: Vec<ExcerptId>,
22756        removed_buffer_ids: Vec<BufferId>,
22757    },
22758    BufferFoldToggled {
22759        ids: Vec<ExcerptId>,
22760        folded: bool,
22761    },
22762    ExcerptsEdited {
22763        ids: Vec<ExcerptId>,
22764    },
22765    ExcerptsExpanded {
22766        ids: Vec<ExcerptId>,
22767    },
22768    BufferEdited,
22769    Edited {
22770        transaction_id: clock::Lamport,
22771    },
22772    Reparsed(BufferId),
22773    Focused,
22774    FocusedIn,
22775    Blurred,
22776    DirtyChanged,
22777    Saved,
22778    TitleChanged,
22779    DiffBaseChanged,
22780    SelectionsChanged {
22781        local: bool,
22782    },
22783    ScrollPositionChanged {
22784        local: bool,
22785        autoscroll: bool,
22786    },
22787    Closed,
22788    TransactionUndone {
22789        transaction_id: clock::Lamport,
22790    },
22791    TransactionBegun {
22792        transaction_id: clock::Lamport,
22793    },
22794    Reloaded,
22795    CursorShapeChanged,
22796    PushedToNavHistory {
22797        anchor: Anchor,
22798        is_deactivate: bool,
22799    },
22800}
22801
22802impl EventEmitter<EditorEvent> for Editor {}
22803
22804impl Focusable for Editor {
22805    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22806        self.focus_handle.clone()
22807    }
22808}
22809
22810impl Render for Editor {
22811    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22812        let settings = ThemeSettings::get_global(cx);
22813
22814        let mut text_style = match self.mode {
22815            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22816                color: cx.theme().colors().editor_foreground,
22817                font_family: settings.ui_font.family.clone(),
22818                font_features: settings.ui_font.features.clone(),
22819                font_fallbacks: settings.ui_font.fallbacks.clone(),
22820                font_size: rems(0.875).into(),
22821                font_weight: settings.ui_font.weight,
22822                line_height: relative(settings.buffer_line_height.value()),
22823                ..Default::default()
22824            },
22825            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22826                color: cx.theme().colors().editor_foreground,
22827                font_family: settings.buffer_font.family.clone(),
22828                font_features: settings.buffer_font.features.clone(),
22829                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22830                font_size: settings.buffer_font_size(cx).into(),
22831                font_weight: settings.buffer_font.weight,
22832                line_height: relative(settings.buffer_line_height.value()),
22833                ..Default::default()
22834            },
22835        };
22836        if let Some(text_style_refinement) = &self.text_style_refinement {
22837            text_style.refine(text_style_refinement)
22838        }
22839
22840        let background = match self.mode {
22841            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22842            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22843            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22844            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22845        };
22846
22847        EditorElement::new(
22848            &cx.entity(),
22849            EditorStyle {
22850                background,
22851                border: cx.theme().colors().border,
22852                local_player: cx.theme().players().local(),
22853                text: text_style,
22854                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22855                syntax: cx.theme().syntax().clone(),
22856                status: cx.theme().status().clone(),
22857                inlay_hints_style: make_inlay_hints_style(cx),
22858                edit_prediction_styles: make_suggestion_styles(cx),
22859                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22860                show_underlines: self.diagnostics_enabled(),
22861            },
22862        )
22863    }
22864}
22865
22866impl EntityInputHandler for Editor {
22867    fn text_for_range(
22868        &mut self,
22869        range_utf16: Range<usize>,
22870        adjusted_range: &mut Option<Range<usize>>,
22871        _: &mut Window,
22872        cx: &mut Context<Self>,
22873    ) -> Option<String> {
22874        let snapshot = self.buffer.read(cx).read(cx);
22875        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22876        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22877        if (start.0..end.0) != range_utf16 {
22878            adjusted_range.replace(start.0..end.0);
22879        }
22880        Some(snapshot.text_for_range(start..end).collect())
22881    }
22882
22883    fn selected_text_range(
22884        &mut self,
22885        ignore_disabled_input: bool,
22886        _: &mut Window,
22887        cx: &mut Context<Self>,
22888    ) -> Option<UTF16Selection> {
22889        // Prevent the IME menu from appearing when holding down an alphabetic key
22890        // while input is disabled.
22891        if !ignore_disabled_input && !self.input_enabled {
22892            return None;
22893        }
22894
22895        let selection = self.selections.newest::<OffsetUtf16>(cx);
22896        let range = selection.range();
22897
22898        Some(UTF16Selection {
22899            range: range.start.0..range.end.0,
22900            reversed: selection.reversed,
22901        })
22902    }
22903
22904    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22905        let snapshot = self.buffer.read(cx).read(cx);
22906        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22907        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22908    }
22909
22910    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22911        self.clear_highlights::<InputComposition>(cx);
22912        self.ime_transaction.take();
22913    }
22914
22915    fn replace_text_in_range(
22916        &mut self,
22917        range_utf16: Option<Range<usize>>,
22918        text: &str,
22919        window: &mut Window,
22920        cx: &mut Context<Self>,
22921    ) {
22922        if !self.input_enabled {
22923            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22924            return;
22925        }
22926
22927        self.transact(window, cx, |this, window, cx| {
22928            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22929                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22930                Some(this.selection_replacement_ranges(range_utf16, cx))
22931            } else {
22932                this.marked_text_ranges(cx)
22933            };
22934
22935            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22936                let newest_selection_id = this.selections.newest_anchor().id;
22937                this.selections
22938                    .all::<OffsetUtf16>(cx)
22939                    .iter()
22940                    .zip(ranges_to_replace.iter())
22941                    .find_map(|(selection, range)| {
22942                        if selection.id == newest_selection_id {
22943                            Some(
22944                                (range.start.0 as isize - selection.head().0 as isize)
22945                                    ..(range.end.0 as isize - selection.head().0 as isize),
22946                            )
22947                        } else {
22948                            None
22949                        }
22950                    })
22951            });
22952
22953            cx.emit(EditorEvent::InputHandled {
22954                utf16_range_to_replace: range_to_replace,
22955                text: text.into(),
22956            });
22957
22958            if let Some(new_selected_ranges) = new_selected_ranges {
22959                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22960                    selections.select_ranges(new_selected_ranges)
22961                });
22962                this.backspace(&Default::default(), window, cx);
22963            }
22964
22965            this.handle_input(text, window, cx);
22966        });
22967
22968        if let Some(transaction) = self.ime_transaction {
22969            self.buffer.update(cx, |buffer, cx| {
22970                buffer.group_until_transaction(transaction, cx);
22971            });
22972        }
22973
22974        self.unmark_text(window, cx);
22975    }
22976
22977    fn replace_and_mark_text_in_range(
22978        &mut self,
22979        range_utf16: Option<Range<usize>>,
22980        text: &str,
22981        new_selected_range_utf16: Option<Range<usize>>,
22982        window: &mut Window,
22983        cx: &mut Context<Self>,
22984    ) {
22985        if !self.input_enabled {
22986            return;
22987        }
22988
22989        let transaction = self.transact(window, cx, |this, window, cx| {
22990            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22991                let snapshot = this.buffer.read(cx).read(cx);
22992                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22993                    for marked_range in &mut marked_ranges {
22994                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22995                        marked_range.start.0 += relative_range_utf16.start;
22996                        marked_range.start =
22997                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22998                        marked_range.end =
22999                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23000                    }
23001                }
23002                Some(marked_ranges)
23003            } else if let Some(range_utf16) = range_utf16 {
23004                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23005                Some(this.selection_replacement_ranges(range_utf16, cx))
23006            } else {
23007                None
23008            };
23009
23010            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23011                let newest_selection_id = this.selections.newest_anchor().id;
23012                this.selections
23013                    .all::<OffsetUtf16>(cx)
23014                    .iter()
23015                    .zip(ranges_to_replace.iter())
23016                    .find_map(|(selection, range)| {
23017                        if selection.id == newest_selection_id {
23018                            Some(
23019                                (range.start.0 as isize - selection.head().0 as isize)
23020                                    ..(range.end.0 as isize - selection.head().0 as isize),
23021                            )
23022                        } else {
23023                            None
23024                        }
23025                    })
23026            });
23027
23028            cx.emit(EditorEvent::InputHandled {
23029                utf16_range_to_replace: range_to_replace,
23030                text: text.into(),
23031            });
23032
23033            if let Some(ranges) = ranges_to_replace {
23034                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23035                    s.select_ranges(ranges)
23036                });
23037            }
23038
23039            let marked_ranges = {
23040                let snapshot = this.buffer.read(cx).read(cx);
23041                this.selections
23042                    .disjoint_anchors()
23043                    .iter()
23044                    .map(|selection| {
23045                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23046                    })
23047                    .collect::<Vec<_>>()
23048            };
23049
23050            if text.is_empty() {
23051                this.unmark_text(window, cx);
23052            } else {
23053                this.highlight_text::<InputComposition>(
23054                    marked_ranges.clone(),
23055                    HighlightStyle {
23056                        underline: Some(UnderlineStyle {
23057                            thickness: px(1.),
23058                            color: None,
23059                            wavy: false,
23060                        }),
23061                        ..Default::default()
23062                    },
23063                    cx,
23064                );
23065            }
23066
23067            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23068            let use_autoclose = this.use_autoclose;
23069            let use_auto_surround = this.use_auto_surround;
23070            this.set_use_autoclose(false);
23071            this.set_use_auto_surround(false);
23072            this.handle_input(text, window, cx);
23073            this.set_use_autoclose(use_autoclose);
23074            this.set_use_auto_surround(use_auto_surround);
23075
23076            if let Some(new_selected_range) = new_selected_range_utf16 {
23077                let snapshot = this.buffer.read(cx).read(cx);
23078                let new_selected_ranges = marked_ranges
23079                    .into_iter()
23080                    .map(|marked_range| {
23081                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23082                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23083                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23084                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23085                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23086                    })
23087                    .collect::<Vec<_>>();
23088
23089                drop(snapshot);
23090                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23091                    selections.select_ranges(new_selected_ranges)
23092                });
23093            }
23094        });
23095
23096        self.ime_transaction = self.ime_transaction.or(transaction);
23097        if let Some(transaction) = self.ime_transaction {
23098            self.buffer.update(cx, |buffer, cx| {
23099                buffer.group_until_transaction(transaction, cx);
23100            });
23101        }
23102
23103        if self.text_highlights::<InputComposition>(cx).is_none() {
23104            self.ime_transaction.take();
23105        }
23106    }
23107
23108    fn bounds_for_range(
23109        &mut self,
23110        range_utf16: Range<usize>,
23111        element_bounds: gpui::Bounds<Pixels>,
23112        window: &mut Window,
23113        cx: &mut Context<Self>,
23114    ) -> Option<gpui::Bounds<Pixels>> {
23115        let text_layout_details = self.text_layout_details(window);
23116        let CharacterDimensions {
23117            em_width,
23118            em_advance,
23119            line_height,
23120        } = self.character_dimensions(window);
23121
23122        let snapshot = self.snapshot(window, cx);
23123        let scroll_position = snapshot.scroll_position();
23124        let scroll_left = scroll_position.x * em_advance;
23125
23126        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23127        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23128            + self.gutter_dimensions.full_width();
23129        let y = line_height * (start.row().as_f32() - scroll_position.y);
23130
23131        Some(Bounds {
23132            origin: element_bounds.origin + point(x, y),
23133            size: size(em_width, line_height),
23134        })
23135    }
23136
23137    fn character_index_for_point(
23138        &mut self,
23139        point: gpui::Point<Pixels>,
23140        _window: &mut Window,
23141        _cx: &mut Context<Self>,
23142    ) -> Option<usize> {
23143        let position_map = self.last_position_map.as_ref()?;
23144        if !position_map.text_hitbox.contains(&point) {
23145            return None;
23146        }
23147        let display_point = position_map.point_for_position(point).previous_valid;
23148        let anchor = position_map
23149            .snapshot
23150            .display_point_to_anchor(display_point, Bias::Left);
23151        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23152        Some(utf16_offset.0)
23153    }
23154}
23155
23156trait SelectionExt {
23157    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23158    fn spanned_rows(
23159        &self,
23160        include_end_if_at_line_start: bool,
23161        map: &DisplaySnapshot,
23162    ) -> Range<MultiBufferRow>;
23163}
23164
23165impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23166    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23167        let start = self
23168            .start
23169            .to_point(&map.buffer_snapshot)
23170            .to_display_point(map);
23171        let end = self
23172            .end
23173            .to_point(&map.buffer_snapshot)
23174            .to_display_point(map);
23175        if self.reversed {
23176            end..start
23177        } else {
23178            start..end
23179        }
23180    }
23181
23182    fn spanned_rows(
23183        &self,
23184        include_end_if_at_line_start: bool,
23185        map: &DisplaySnapshot,
23186    ) -> Range<MultiBufferRow> {
23187        let start = self.start.to_point(&map.buffer_snapshot);
23188        let mut end = self.end.to_point(&map.buffer_snapshot);
23189        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23190            end.row -= 1;
23191        }
23192
23193        let buffer_start = map.prev_line_boundary(start).0;
23194        let buffer_end = map.next_line_boundary(end).0;
23195        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23196    }
23197}
23198
23199impl<T: InvalidationRegion> InvalidationStack<T> {
23200    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23201    where
23202        S: Clone + ToOffset,
23203    {
23204        while let Some(region) = self.last() {
23205            let all_selections_inside_invalidation_ranges =
23206                if selections.len() == region.ranges().len() {
23207                    selections
23208                        .iter()
23209                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23210                        .all(|(selection, invalidation_range)| {
23211                            let head = selection.head().to_offset(buffer);
23212                            invalidation_range.start <= head && invalidation_range.end >= head
23213                        })
23214                } else {
23215                    false
23216                };
23217
23218            if all_selections_inside_invalidation_ranges {
23219                break;
23220            } else {
23221                self.pop();
23222            }
23223        }
23224    }
23225}
23226
23227impl<T> Default for InvalidationStack<T> {
23228    fn default() -> Self {
23229        Self(Default::default())
23230    }
23231}
23232
23233impl<T> Deref for InvalidationStack<T> {
23234    type Target = Vec<T>;
23235
23236    fn deref(&self) -> &Self::Target {
23237        &self.0
23238    }
23239}
23240
23241impl<T> DerefMut for InvalidationStack<T> {
23242    fn deref_mut(&mut self) -> &mut Self::Target {
23243        &mut self.0
23244    }
23245}
23246
23247impl InvalidationRegion for SnippetState {
23248    fn ranges(&self) -> &[Range<Anchor>] {
23249        &self.ranges[self.active_index]
23250    }
23251}
23252
23253fn edit_prediction_edit_text(
23254    current_snapshot: &BufferSnapshot,
23255    edits: &[(Range<Anchor>, String)],
23256    edit_preview: &EditPreview,
23257    include_deletions: bool,
23258    cx: &App,
23259) -> HighlightedText {
23260    let edits = edits
23261        .iter()
23262        .map(|(anchor, text)| {
23263            (
23264                anchor.start.text_anchor..anchor.end.text_anchor,
23265                text.clone(),
23266            )
23267        })
23268        .collect::<Vec<_>>();
23269
23270    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23271}
23272
23273pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23274    match severity {
23275        lsp::DiagnosticSeverity::ERROR => colors.error,
23276        lsp::DiagnosticSeverity::WARNING => colors.warning,
23277        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23278        lsp::DiagnosticSeverity::HINT => colors.info,
23279        _ => colors.ignored,
23280    }
23281}
23282
23283pub fn styled_runs_for_code_label<'a>(
23284    label: &'a CodeLabel,
23285    syntax_theme: &'a theme::SyntaxTheme,
23286) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23287    let fade_out = HighlightStyle {
23288        fade_out: Some(0.35),
23289        ..Default::default()
23290    };
23291
23292    let mut prev_end = label.filter_range.end;
23293    label
23294        .runs
23295        .iter()
23296        .enumerate()
23297        .flat_map(move |(ix, (range, highlight_id))| {
23298            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23299                style
23300            } else {
23301                return Default::default();
23302            };
23303            let mut muted_style = style;
23304            muted_style.highlight(fade_out);
23305
23306            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23307            if range.start >= label.filter_range.end {
23308                if range.start > prev_end {
23309                    runs.push((prev_end..range.start, fade_out));
23310                }
23311                runs.push((range.clone(), muted_style));
23312            } else if range.end <= label.filter_range.end {
23313                runs.push((range.clone(), style));
23314            } else {
23315                runs.push((range.start..label.filter_range.end, style));
23316                runs.push((label.filter_range.end..range.end, muted_style));
23317            }
23318            prev_end = cmp::max(prev_end, range.end);
23319
23320            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23321                runs.push((prev_end..label.text.len(), fade_out));
23322            }
23323
23324            runs
23325        })
23326}
23327
23328pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23329    let mut prev_index = 0;
23330    let mut prev_codepoint: Option<char> = None;
23331    text.char_indices()
23332        .chain([(text.len(), '\0')])
23333        .filter_map(move |(index, codepoint)| {
23334            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23335            let is_boundary = index == text.len()
23336                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23337                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23338            if is_boundary {
23339                let chunk = &text[prev_index..index];
23340                prev_index = index;
23341                Some(chunk)
23342            } else {
23343                None
23344            }
23345        })
23346}
23347
23348pub trait RangeToAnchorExt: Sized {
23349    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23350
23351    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23352        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23353        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23354    }
23355}
23356
23357impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23358    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23359        let start_offset = self.start.to_offset(snapshot);
23360        let end_offset = self.end.to_offset(snapshot);
23361        if start_offset == end_offset {
23362            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23363        } else {
23364            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23365        }
23366    }
23367}
23368
23369pub trait RowExt {
23370    fn as_f32(&self) -> f32;
23371
23372    fn next_row(&self) -> Self;
23373
23374    fn previous_row(&self) -> Self;
23375
23376    fn minus(&self, other: Self) -> u32;
23377}
23378
23379impl RowExt for DisplayRow {
23380    fn as_f32(&self) -> f32 {
23381        self.0 as f32
23382    }
23383
23384    fn next_row(&self) -> Self {
23385        Self(self.0 + 1)
23386    }
23387
23388    fn previous_row(&self) -> Self {
23389        Self(self.0.saturating_sub(1))
23390    }
23391
23392    fn minus(&self, other: Self) -> u32 {
23393        self.0 - other.0
23394    }
23395}
23396
23397impl RowExt for MultiBufferRow {
23398    fn as_f32(&self) -> f32 {
23399        self.0 as f32
23400    }
23401
23402    fn next_row(&self) -> Self {
23403        Self(self.0 + 1)
23404    }
23405
23406    fn previous_row(&self) -> Self {
23407        Self(self.0.saturating_sub(1))
23408    }
23409
23410    fn minus(&self, other: Self) -> u32 {
23411        self.0 - other.0
23412    }
23413}
23414
23415trait RowRangeExt {
23416    type Row;
23417
23418    fn len(&self) -> usize;
23419
23420    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23421}
23422
23423impl RowRangeExt for Range<MultiBufferRow> {
23424    type Row = MultiBufferRow;
23425
23426    fn len(&self) -> usize {
23427        (self.end.0 - self.start.0) as usize
23428    }
23429
23430    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23431        (self.start.0..self.end.0).map(MultiBufferRow)
23432    }
23433}
23434
23435impl RowRangeExt for Range<DisplayRow> {
23436    type Row = DisplayRow;
23437
23438    fn len(&self) -> usize {
23439        (self.end.0 - self.start.0) as usize
23440    }
23441
23442    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23443        (self.start.0..self.end.0).map(DisplayRow)
23444    }
23445}
23446
23447/// If select range has more than one line, we
23448/// just point the cursor to range.start.
23449fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23450    if range.start.row == range.end.row {
23451        range
23452    } else {
23453        range.start..range.start
23454    }
23455}
23456pub struct KillRing(ClipboardItem);
23457impl Global for KillRing {}
23458
23459const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23460
23461enum BreakpointPromptEditAction {
23462    Log,
23463    Condition,
23464    HitCondition,
23465}
23466
23467struct BreakpointPromptEditor {
23468    pub(crate) prompt: Entity<Editor>,
23469    editor: WeakEntity<Editor>,
23470    breakpoint_anchor: Anchor,
23471    breakpoint: Breakpoint,
23472    edit_action: BreakpointPromptEditAction,
23473    block_ids: HashSet<CustomBlockId>,
23474    editor_margins: Arc<Mutex<EditorMargins>>,
23475    _subscriptions: Vec<Subscription>,
23476}
23477
23478impl BreakpointPromptEditor {
23479    const MAX_LINES: u8 = 4;
23480
23481    fn new(
23482        editor: WeakEntity<Editor>,
23483        breakpoint_anchor: Anchor,
23484        breakpoint: Breakpoint,
23485        edit_action: BreakpointPromptEditAction,
23486        window: &mut Window,
23487        cx: &mut Context<Self>,
23488    ) -> Self {
23489        let base_text = match edit_action {
23490            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23491            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23492            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23493        }
23494        .map(|msg| msg.to_string())
23495        .unwrap_or_default();
23496
23497        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23498        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23499
23500        let prompt = cx.new(|cx| {
23501            let mut prompt = Editor::new(
23502                EditorMode::AutoHeight {
23503                    min_lines: 1,
23504                    max_lines: Some(Self::MAX_LINES as usize),
23505                },
23506                buffer,
23507                None,
23508                window,
23509                cx,
23510            );
23511            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23512            prompt.set_show_cursor_when_unfocused(false, cx);
23513            prompt.set_placeholder_text(
23514                match edit_action {
23515                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23516                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23517                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23518                },
23519                cx,
23520            );
23521
23522            prompt
23523        });
23524
23525        Self {
23526            prompt,
23527            editor,
23528            breakpoint_anchor,
23529            breakpoint,
23530            edit_action,
23531            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23532            block_ids: Default::default(),
23533            _subscriptions: vec![],
23534        }
23535    }
23536
23537    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23538        self.block_ids.extend(block_ids)
23539    }
23540
23541    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23542        if let Some(editor) = self.editor.upgrade() {
23543            let message = self
23544                .prompt
23545                .read(cx)
23546                .buffer
23547                .read(cx)
23548                .as_singleton()
23549                .expect("A multi buffer in breakpoint prompt isn't possible")
23550                .read(cx)
23551                .as_rope()
23552                .to_string();
23553
23554            editor.update(cx, |editor, cx| {
23555                editor.edit_breakpoint_at_anchor(
23556                    self.breakpoint_anchor,
23557                    self.breakpoint.clone(),
23558                    match self.edit_action {
23559                        BreakpointPromptEditAction::Log => {
23560                            BreakpointEditAction::EditLogMessage(message.into())
23561                        }
23562                        BreakpointPromptEditAction::Condition => {
23563                            BreakpointEditAction::EditCondition(message.into())
23564                        }
23565                        BreakpointPromptEditAction::HitCondition => {
23566                            BreakpointEditAction::EditHitCondition(message.into())
23567                        }
23568                    },
23569                    cx,
23570                );
23571
23572                editor.remove_blocks(self.block_ids.clone(), None, cx);
23573                cx.focus_self(window);
23574            });
23575        }
23576    }
23577
23578    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23579        self.editor
23580            .update(cx, |editor, cx| {
23581                editor.remove_blocks(self.block_ids.clone(), None, cx);
23582                window.focus(&editor.focus_handle);
23583            })
23584            .log_err();
23585    }
23586
23587    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23588        let settings = ThemeSettings::get_global(cx);
23589        let text_style = TextStyle {
23590            color: if self.prompt.read(cx).read_only(cx) {
23591                cx.theme().colors().text_disabled
23592            } else {
23593                cx.theme().colors().text
23594            },
23595            font_family: settings.buffer_font.family.clone(),
23596            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23597            font_size: settings.buffer_font_size(cx).into(),
23598            font_weight: settings.buffer_font.weight,
23599            line_height: relative(settings.buffer_line_height.value()),
23600            ..Default::default()
23601        };
23602        EditorElement::new(
23603            &self.prompt,
23604            EditorStyle {
23605                background: cx.theme().colors().editor_background,
23606                local_player: cx.theme().players().local(),
23607                text: text_style,
23608                ..Default::default()
23609            },
23610        )
23611    }
23612}
23613
23614impl Render for BreakpointPromptEditor {
23615    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23616        let editor_margins = *self.editor_margins.lock();
23617        let gutter_dimensions = editor_margins.gutter;
23618        h_flex()
23619            .key_context("Editor")
23620            .bg(cx.theme().colors().editor_background)
23621            .border_y_1()
23622            .border_color(cx.theme().status().info_border)
23623            .size_full()
23624            .py(window.line_height() / 2.5)
23625            .on_action(cx.listener(Self::confirm))
23626            .on_action(cx.listener(Self::cancel))
23627            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23628            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23629    }
23630}
23631
23632impl Focusable for BreakpointPromptEditor {
23633    fn focus_handle(&self, cx: &App) -> FocusHandle {
23634        self.prompt.focus_handle(cx)
23635    }
23636}
23637
23638fn all_edits_insertions_or_deletions(
23639    edits: &Vec<(Range<Anchor>, String)>,
23640    snapshot: &MultiBufferSnapshot,
23641) -> bool {
23642    let mut all_insertions = true;
23643    let mut all_deletions = true;
23644
23645    for (range, new_text) in edits.iter() {
23646        let range_is_empty = range.to_offset(&snapshot).is_empty();
23647        let text_is_empty = new_text.is_empty();
23648
23649        if range_is_empty != text_is_empty {
23650            if range_is_empty {
23651                all_deletions = false;
23652            } else {
23653                all_insertions = false;
23654            }
23655        } else {
23656            return false;
23657        }
23658
23659        if !all_insertions && !all_deletions {
23660            return false;
23661        }
23662    }
23663    all_insertions || all_deletions
23664}
23665
23666struct MissingEditPredictionKeybindingTooltip;
23667
23668impl Render for MissingEditPredictionKeybindingTooltip {
23669    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23670        ui::tooltip_container(window, cx, |container, _, cx| {
23671            container
23672                .flex_shrink_0()
23673                .max_w_80()
23674                .min_h(rems_from_px(124.))
23675                .justify_between()
23676                .child(
23677                    v_flex()
23678                        .flex_1()
23679                        .text_ui_sm(cx)
23680                        .child(Label::new("Conflict with Accept Keybinding"))
23681                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23682                )
23683                .child(
23684                    h_flex()
23685                        .pb_1()
23686                        .gap_1()
23687                        .items_end()
23688                        .w_full()
23689                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23690                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23691                        }))
23692                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23693                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23694                        })),
23695                )
23696        })
23697    }
23698}
23699
23700#[derive(Debug, Clone, Copy, PartialEq)]
23701pub struct LineHighlight {
23702    pub background: Background,
23703    pub border: Option<gpui::Hsla>,
23704    pub include_gutter: bool,
23705    pub type_id: Option<TypeId>,
23706}
23707
23708struct LineManipulationResult {
23709    pub new_text: String,
23710    pub line_count_before: usize,
23711    pub line_count_after: usize,
23712}
23713
23714fn render_diff_hunk_controls(
23715    row: u32,
23716    status: &DiffHunkStatus,
23717    hunk_range: Range<Anchor>,
23718    is_created_file: bool,
23719    line_height: Pixels,
23720    editor: &Entity<Editor>,
23721    _window: &mut Window,
23722    cx: &mut App,
23723) -> AnyElement {
23724    h_flex()
23725        .h(line_height)
23726        .mr_1()
23727        .gap_1()
23728        .px_0p5()
23729        .pb_1()
23730        .border_x_1()
23731        .border_b_1()
23732        .border_color(cx.theme().colors().border_variant)
23733        .rounded_b_lg()
23734        .bg(cx.theme().colors().editor_background)
23735        .gap_1()
23736        .block_mouse_except_scroll()
23737        .shadow_md()
23738        .child(if status.has_secondary_hunk() {
23739            Button::new(("stage", row as u64), "Stage")
23740                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23741                .tooltip({
23742                    let focus_handle = editor.focus_handle(cx);
23743                    move |window, cx| {
23744                        Tooltip::for_action_in(
23745                            "Stage Hunk",
23746                            &::git::ToggleStaged,
23747                            &focus_handle,
23748                            window,
23749                            cx,
23750                        )
23751                    }
23752                })
23753                .on_click({
23754                    let editor = editor.clone();
23755                    move |_event, _window, cx| {
23756                        editor.update(cx, |editor, cx| {
23757                            editor.stage_or_unstage_diff_hunks(
23758                                true,
23759                                vec![hunk_range.start..hunk_range.start],
23760                                cx,
23761                            );
23762                        });
23763                    }
23764                })
23765        } else {
23766            Button::new(("unstage", row as u64), "Unstage")
23767                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23768                .tooltip({
23769                    let focus_handle = editor.focus_handle(cx);
23770                    move |window, cx| {
23771                        Tooltip::for_action_in(
23772                            "Unstage Hunk",
23773                            &::git::ToggleStaged,
23774                            &focus_handle,
23775                            window,
23776                            cx,
23777                        )
23778                    }
23779                })
23780                .on_click({
23781                    let editor = editor.clone();
23782                    move |_event, _window, cx| {
23783                        editor.update(cx, |editor, cx| {
23784                            editor.stage_or_unstage_diff_hunks(
23785                                false,
23786                                vec![hunk_range.start..hunk_range.start],
23787                                cx,
23788                            );
23789                        });
23790                    }
23791                })
23792        })
23793        .child(
23794            Button::new(("restore", row as u64), "Restore")
23795                .tooltip({
23796                    let focus_handle = editor.focus_handle(cx);
23797                    move |window, cx| {
23798                        Tooltip::for_action_in(
23799                            "Restore Hunk",
23800                            &::git::Restore,
23801                            &focus_handle,
23802                            window,
23803                            cx,
23804                        )
23805                    }
23806                })
23807                .on_click({
23808                    let editor = editor.clone();
23809                    move |_event, window, cx| {
23810                        editor.update(cx, |editor, cx| {
23811                            let snapshot = editor.snapshot(window, cx);
23812                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23813                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23814                        });
23815                    }
23816                })
23817                .disabled(is_created_file),
23818        )
23819        .when(
23820            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23821            |el| {
23822                el.child(
23823                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23824                        .shape(IconButtonShape::Square)
23825                        .icon_size(IconSize::Small)
23826                        // .disabled(!has_multiple_hunks)
23827                        .tooltip({
23828                            let focus_handle = editor.focus_handle(cx);
23829                            move |window, cx| {
23830                                Tooltip::for_action_in(
23831                                    "Next Hunk",
23832                                    &GoToHunk,
23833                                    &focus_handle,
23834                                    window,
23835                                    cx,
23836                                )
23837                            }
23838                        })
23839                        .on_click({
23840                            let editor = editor.clone();
23841                            move |_event, window, cx| {
23842                                editor.update(cx, |editor, cx| {
23843                                    let snapshot = editor.snapshot(window, cx);
23844                                    let position =
23845                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23846                                    editor.go_to_hunk_before_or_after_position(
23847                                        &snapshot,
23848                                        position,
23849                                        Direction::Next,
23850                                        window,
23851                                        cx,
23852                                    );
23853                                    editor.expand_selected_diff_hunks(cx);
23854                                });
23855                            }
23856                        }),
23857                )
23858                .child(
23859                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23860                        .shape(IconButtonShape::Square)
23861                        .icon_size(IconSize::Small)
23862                        // .disabled(!has_multiple_hunks)
23863                        .tooltip({
23864                            let focus_handle = editor.focus_handle(cx);
23865                            move |window, cx| {
23866                                Tooltip::for_action_in(
23867                                    "Previous Hunk",
23868                                    &GoToPreviousHunk,
23869                                    &focus_handle,
23870                                    window,
23871                                    cx,
23872                                )
23873                            }
23874                        })
23875                        .on_click({
23876                            let editor = editor.clone();
23877                            move |_event, window, cx| {
23878                                editor.update(cx, |editor, cx| {
23879                                    let snapshot = editor.snapshot(window, cx);
23880                                    let point =
23881                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23882                                    editor.go_to_hunk_before_or_after_position(
23883                                        &snapshot,
23884                                        point,
23885                                        Direction::Prev,
23886                                        window,
23887                                        cx,
23888                                    );
23889                                    editor.expand_selected_diff_hunks(cx);
23890                                });
23891                            }
23892                        }),
23893                )
23894            },
23895        )
23896        .into_any_element()
23897}