editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_colors;
   33mod lsp_ext;
   34mod mouse_context_menu;
   35pub mod movement;
   36mod persistence;
   37mod proposed_changes_editor;
   38mod rust_analyzer_ext;
   39pub mod scroll;
   40mod selections_collection;
   41pub mod tasks;
   42
   43#[cfg(test)]
   44mod code_completion_tests;
   45#[cfg(test)]
   46mod editor_tests;
   47#[cfg(test)]
   48mod inline_completion_tests;
   49mod signature_help;
   50#[cfg(any(test, feature = "test-support"))]
   51pub mod test;
   52
   53pub(crate) use actions::*;
   54pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   55pub use editor_settings::{
   56    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   57    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap, ShowScrollbar,
   58};
   59pub use editor_settings_controls::*;
   60pub use element::{
   61    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   62};
   63pub use git::blame::BlameRenderer;
   64pub use hover_popover::hover_markdown_style;
   65pub use inline_completion::Direction;
   66pub use items::MAX_TAB_TITLE_LEN;
   67pub use lsp::CompletionContext;
   68pub use lsp_ext::lsp_tasks;
   69pub use multi_buffer::{
   70    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   71    RowInfo, ToOffset, ToPoint,
   72};
   73pub use proposed_changes_editor::{
   74    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
   75};
   76pub use text::Bias;
   77
   78use ::git::{
   79    Restore,
   80    blame::{BlameEntry, ParsedCommitMessage},
   81};
   82use aho_corasick::AhoCorasick;
   83use anyhow::{Context as _, Result, anyhow};
   84use blink_manager::BlinkManager;
   85use buffer_diff::DiffHunkStatus;
   86use client::{Collaborator, DisableAiSettings, ParticipantIndex};
   87use clock::{AGENT_REPLICA_ID, ReplicaId};
   88use code_context_menus::{
   89    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   90    CompletionsMenu, ContextMenuOrigin,
   91};
   92use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   93use convert_case::{Case, Casing};
   94use dap::TelemetrySpawnLocation;
   95use display_map::*;
   96use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   97use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   98use futures::{
   99    FutureExt, StreamExt as _,
  100    future::{self, Shared, join},
  101    stream::FuturesUnordered,
  102};
  103use fuzzy::{StringMatch, StringMatchCandidate};
  104use git::blame::{GitBlame, GlobalBlameRenderer};
  105use gpui::{
  106    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  107    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  108    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  109    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  110    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  111    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  112    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  113    div, point, prelude::*, pulsating_between, px, relative, size,
  114};
  115use highlight_matching_bracket::refresh_matching_bracket_highlights;
  116use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  117use hover_popover::{HoverState, hide_hover};
  118use indent_guides::ActiveIndentGuidesState;
  119use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  120use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  121use itertools::Itertools;
  122use language::{
  123    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  124    BufferSnapshot, Capability, CharClassifier, CharKind, CodeLabel, CursorShape, DiagnosticEntry,
  125    DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind, IndentSize,
  126    Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal, TextObject,
  127    TransactionId, TreeSitterOptions, WordsQuery,
  128    language_settings::{
  129        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  130        all_language_settings, language_settings,
  131    },
  132    point_from_lsp, point_to_lsp, text_diff_with_options,
  133};
  134use linked_editing_ranges::refresh_linked_ranges;
  135use lsp::{
  136    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  137    LanguageServerId, LanguageServerName,
  138};
  139use lsp_colors::LspColorData;
  140use markdown::Markdown;
  141use mouse_context_menu::MouseContextMenu;
  142use movement::TextLayoutDetails;
  143use multi_buffer::{
  144    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  145    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  146};
  147use parking_lot::Mutex;
  148use persistence::DB;
  149use project::{
  150    BreakpointWithPosition, CodeAction, Completion, CompletionIntent, CompletionResponse,
  151    CompletionSource, DocumentHighlight, InlayHint, Location, LocationLink, PrepareRenameResponse,
  152    Project, ProjectItem, ProjectPath, ProjectTransaction, TaskSourceKind,
  153    debugger::breakpoint_store::Breakpoint,
  154    debugger::{
  155        breakpoint_store::{
  156            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  157            BreakpointStoreEvent,
  158        },
  159        session::{Session, SessionEvent},
  160    },
  161    git_store::{GitStoreEvent, RepositoryEvent},
  162    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  163    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter},
  164    project_settings::{GitGutterSetting, ProjectSettings},
  165};
  166use rand::{seq::SliceRandom, thread_rng};
  167use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  168use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  169use selections_collection::{
  170    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  171};
  172use serde::{Deserialize, Serialize};
  173use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  174use smallvec::{SmallVec, smallvec};
  175use snippet::Snippet;
  176use std::{
  177    any::TypeId,
  178    borrow::Cow,
  179    cell::OnceCell,
  180    cell::RefCell,
  181    cmp::{self, Ordering, Reverse},
  182    iter::Peekable,
  183    mem,
  184    num::NonZeroU32,
  185    ops::Not,
  186    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  187    path::{Path, PathBuf},
  188    rc::Rc,
  189    sync::Arc,
  190    time::{Duration, Instant},
  191};
  192use sum_tree::TreeMap;
  193use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  194use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  195use theme::{
  196    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  197    observe_buffer_font_size_adjustment,
  198};
  199use ui::{
  200    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  201    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  202};
  203use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  204use workspace::{
  205    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  206    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  207    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  208    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  209    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  210    searchable::SearchEvent,
  211};
  212
  213use crate::{
  214    code_context_menus::CompletionsMenuSource,
  215    editor_settings::MultiCursorModifier,
  216    hover_links::{find_url, find_url_from_range},
  217    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  218};
  219
  220pub const FILE_HEADER_HEIGHT: u32 = 2;
  221pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  222pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  223const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  224const MAX_LINE_LEN: usize = 1024;
  225const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  226const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  227pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  228#[doc(hidden)]
  229pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  230const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  231
  232pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  233pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  234pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  235
  236pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  237pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  238pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  239
  240pub type RenderDiffHunkControlsFn = Arc<
  241    dyn Fn(
  242        u32,
  243        &DiffHunkStatus,
  244        Range<Anchor>,
  245        bool,
  246        Pixels,
  247        &Entity<Editor>,
  248        &mut Window,
  249        &mut App,
  250    ) -> AnyElement,
  251>;
  252
  253struct InlineValueCache {
  254    enabled: bool,
  255    inlays: Vec<InlayId>,
  256    refresh_task: Task<Option<()>>,
  257}
  258
  259impl InlineValueCache {
  260    fn new(enabled: bool) -> Self {
  261        Self {
  262            enabled,
  263            inlays: Vec::new(),
  264            refresh_task: Task::ready(None),
  265        }
  266    }
  267}
  268
  269#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  270pub enum InlayId {
  271    InlineCompletion(usize),
  272    DebuggerValue(usize),
  273    // LSP
  274    Hint(usize),
  275    Color(usize),
  276}
  277
  278impl InlayId {
  279    fn id(&self) -> usize {
  280        match self {
  281            Self::InlineCompletion(id) => *id,
  282            Self::DebuggerValue(id) => *id,
  283            Self::Hint(id) => *id,
  284            Self::Color(id) => *id,
  285        }
  286    }
  287}
  288
  289pub enum ActiveDebugLine {}
  290pub enum DebugStackFrameLine {}
  291enum DocumentHighlightRead {}
  292enum DocumentHighlightWrite {}
  293enum InputComposition {}
  294pub enum PendingInput {}
  295enum SelectedTextHighlight {}
  296
  297pub enum ConflictsOuter {}
  298pub enum ConflictsOurs {}
  299pub enum ConflictsTheirs {}
  300pub enum ConflictsOursMarker {}
  301pub enum ConflictsTheirsMarker {}
  302
  303#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  304pub enum Navigated {
  305    Yes,
  306    No,
  307}
  308
  309impl Navigated {
  310    pub fn from_bool(yes: bool) -> Navigated {
  311        if yes { Navigated::Yes } else { Navigated::No }
  312    }
  313}
  314
  315#[derive(Debug, Clone, PartialEq, Eq)]
  316enum DisplayDiffHunk {
  317    Folded {
  318        display_row: DisplayRow,
  319    },
  320    Unfolded {
  321        is_created_file: bool,
  322        diff_base_byte_range: Range<usize>,
  323        display_row_range: Range<DisplayRow>,
  324        multi_buffer_range: Range<Anchor>,
  325        status: DiffHunkStatus,
  326    },
  327}
  328
  329pub enum HideMouseCursorOrigin {
  330    TypingAction,
  331    MovementAction,
  332}
  333
  334pub fn init_settings(cx: &mut App) {
  335    EditorSettings::register(cx);
  336}
  337
  338pub fn init(cx: &mut App) {
  339    init_settings(cx);
  340
  341    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  342
  343    workspace::register_project_item::<Editor>(cx);
  344    workspace::FollowableViewRegistry::register::<Editor>(cx);
  345    workspace::register_serializable_item::<Editor>(cx);
  346
  347    cx.observe_new(
  348        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  349            workspace.register_action(Editor::new_file);
  350            workspace.register_action(Editor::new_file_vertical);
  351            workspace.register_action(Editor::new_file_horizontal);
  352            workspace.register_action(Editor::cancel_language_server_work);
  353            workspace.register_action(Editor::toggle_focus);
  354        },
  355    )
  356    .detach();
  357
  358    cx.on_action(move |_: &workspace::NewFile, cx| {
  359        let app_state = workspace::AppState::global(cx);
  360        if let Some(app_state) = app_state.upgrade() {
  361            workspace::open_new(
  362                Default::default(),
  363                app_state,
  364                cx,
  365                |workspace, window, cx| {
  366                    Editor::new_file(workspace, &Default::default(), window, cx)
  367                },
  368            )
  369            .detach();
  370        }
  371    });
  372    cx.on_action(move |_: &workspace::NewWindow, cx| {
  373        let app_state = workspace::AppState::global(cx);
  374        if let Some(app_state) = app_state.upgrade() {
  375            workspace::open_new(
  376                Default::default(),
  377                app_state,
  378                cx,
  379                |workspace, window, cx| {
  380                    cx.activate(true);
  381                    Editor::new_file(workspace, &Default::default(), window, cx)
  382                },
  383            )
  384            .detach();
  385        }
  386    });
  387}
  388
  389pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  390    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  391}
  392
  393pub trait DiagnosticRenderer {
  394    fn render_group(
  395        &self,
  396        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  397        buffer_id: BufferId,
  398        snapshot: EditorSnapshot,
  399        editor: WeakEntity<Editor>,
  400        cx: &mut App,
  401    ) -> Vec<BlockProperties<Anchor>>;
  402
  403    fn render_hover(
  404        &self,
  405        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  406        range: Range<Point>,
  407        buffer_id: BufferId,
  408        cx: &mut App,
  409    ) -> Option<Entity<markdown::Markdown>>;
  410
  411    fn open_link(
  412        &self,
  413        editor: &mut Editor,
  414        link: SharedString,
  415        window: &mut Window,
  416        cx: &mut Context<Editor>,
  417    );
  418}
  419
  420pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  421
  422impl GlobalDiagnosticRenderer {
  423    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  424        cx.try_global::<Self>().map(|g| g.0.clone())
  425    }
  426}
  427
  428impl gpui::Global for GlobalDiagnosticRenderer {}
  429pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  430    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  431}
  432
  433pub struct SearchWithinRange;
  434
  435trait InvalidationRegion {
  436    fn ranges(&self) -> &[Range<Anchor>];
  437}
  438
  439#[derive(Clone, Debug, PartialEq)]
  440pub enum SelectPhase {
  441    Begin {
  442        position: DisplayPoint,
  443        add: bool,
  444        click_count: usize,
  445    },
  446    BeginColumnar {
  447        position: DisplayPoint,
  448        reset: bool,
  449        mode: ColumnarMode,
  450        goal_column: u32,
  451    },
  452    Extend {
  453        position: DisplayPoint,
  454        click_count: usize,
  455    },
  456    Update {
  457        position: DisplayPoint,
  458        goal_column: u32,
  459        scroll_delta: gpui::Point<f32>,
  460    },
  461    End,
  462}
  463
  464#[derive(Clone, Debug, PartialEq)]
  465pub enum ColumnarMode {
  466    FromMouse,
  467    FromSelection,
  468}
  469
  470#[derive(Clone, Debug)]
  471pub enum SelectMode {
  472    Character,
  473    Word(Range<Anchor>),
  474    Line(Range<Anchor>),
  475    All,
  476}
  477
  478#[derive(Clone, PartialEq, Eq, Debug)]
  479pub enum EditorMode {
  480    SingleLine,
  481    AutoHeight {
  482        min_lines: usize,
  483        max_lines: Option<usize>,
  484    },
  485    Full {
  486        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  487        scale_ui_elements_with_buffer_font_size: bool,
  488        /// When set to `true`, the editor will render a background for the active line.
  489        show_active_line_background: bool,
  490        /// When set to `true`, the editor's height will be determined by its content.
  491        sized_by_content: bool,
  492    },
  493    Minimap {
  494        parent: WeakEntity<Editor>,
  495    },
  496}
  497
  498impl EditorMode {
  499    pub fn full() -> Self {
  500        Self::Full {
  501            scale_ui_elements_with_buffer_font_size: true,
  502            show_active_line_background: true,
  503            sized_by_content: false,
  504        }
  505    }
  506
  507    #[inline]
  508    pub fn is_full(&self) -> bool {
  509        matches!(self, Self::Full { .. })
  510    }
  511
  512    #[inline]
  513    pub fn is_single_line(&self) -> bool {
  514        matches!(self, Self::SingleLine { .. })
  515    }
  516
  517    #[inline]
  518    fn is_minimap(&self) -> bool {
  519        matches!(self, Self::Minimap { .. })
  520    }
  521}
  522
  523#[derive(Copy, Clone, Debug)]
  524pub enum SoftWrap {
  525    /// Prefer not to wrap at all.
  526    ///
  527    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  528    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  529    GitDiff,
  530    /// Prefer a single line generally, unless an overly long line is encountered.
  531    None,
  532    /// Soft wrap lines that exceed the editor width.
  533    EditorWidth,
  534    /// Soft wrap lines at the preferred line length.
  535    Column(u32),
  536    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  537    Bounded(u32),
  538}
  539
  540#[derive(Clone)]
  541pub struct EditorStyle {
  542    pub background: Hsla,
  543    pub border: Hsla,
  544    pub local_player: PlayerColor,
  545    pub text: TextStyle,
  546    pub scrollbar_width: Pixels,
  547    pub syntax: Arc<SyntaxTheme>,
  548    pub status: StatusColors,
  549    pub inlay_hints_style: HighlightStyle,
  550    pub inline_completion_styles: InlineCompletionStyles,
  551    pub unnecessary_code_fade: f32,
  552    pub show_underlines: bool,
  553}
  554
  555impl Default for EditorStyle {
  556    fn default() -> Self {
  557        Self {
  558            background: Hsla::default(),
  559            border: Hsla::default(),
  560            local_player: PlayerColor::default(),
  561            text: TextStyle::default(),
  562            scrollbar_width: Pixels::default(),
  563            syntax: Default::default(),
  564            // HACK: Status colors don't have a real default.
  565            // We should look into removing the status colors from the editor
  566            // style and retrieve them directly from the theme.
  567            status: StatusColors::dark(),
  568            inlay_hints_style: HighlightStyle::default(),
  569            inline_completion_styles: InlineCompletionStyles {
  570                insertion: HighlightStyle::default(),
  571                whitespace: HighlightStyle::default(),
  572            },
  573            unnecessary_code_fade: Default::default(),
  574            show_underlines: true,
  575        }
  576    }
  577}
  578
  579pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  580    let show_background = language_settings::language_settings(None, None, cx)
  581        .inlay_hints
  582        .show_background;
  583
  584    HighlightStyle {
  585        color: Some(cx.theme().status().hint),
  586        background_color: show_background.then(|| cx.theme().status().hint_background),
  587        ..HighlightStyle::default()
  588    }
  589}
  590
  591pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  592    InlineCompletionStyles {
  593        insertion: HighlightStyle {
  594            color: Some(cx.theme().status().predictive),
  595            ..HighlightStyle::default()
  596        },
  597        whitespace: HighlightStyle {
  598            background_color: Some(cx.theme().status().created_background),
  599            ..HighlightStyle::default()
  600        },
  601    }
  602}
  603
  604type CompletionId = usize;
  605
  606pub(crate) enum EditDisplayMode {
  607    TabAccept,
  608    DiffPopover,
  609    Inline,
  610}
  611
  612enum InlineCompletion {
  613    Edit {
  614        edits: Vec<(Range<Anchor>, String)>,
  615        edit_preview: Option<EditPreview>,
  616        display_mode: EditDisplayMode,
  617        snapshot: BufferSnapshot,
  618    },
  619    Move {
  620        target: Anchor,
  621        snapshot: BufferSnapshot,
  622    },
  623}
  624
  625struct InlineCompletionState {
  626    inlay_ids: Vec<InlayId>,
  627    completion: InlineCompletion,
  628    completion_id: Option<SharedString>,
  629    invalidation_range: Range<Anchor>,
  630}
  631
  632enum EditPredictionSettings {
  633    Disabled,
  634    Enabled {
  635        show_in_menu: bool,
  636        preview_requires_modifier: bool,
  637    },
  638}
  639
  640enum InlineCompletionHighlight {}
  641
  642#[derive(Debug, Clone)]
  643struct InlineDiagnostic {
  644    message: SharedString,
  645    group_id: usize,
  646    is_primary: bool,
  647    start: Point,
  648    severity: lsp::DiagnosticSeverity,
  649}
  650
  651pub enum MenuInlineCompletionsPolicy {
  652    Never,
  653    ByProvider,
  654}
  655
  656pub enum EditPredictionPreview {
  657    /// Modifier is not pressed
  658    Inactive { released_too_fast: bool },
  659    /// Modifier pressed
  660    Active {
  661        since: Instant,
  662        previous_scroll_position: Option<ScrollAnchor>,
  663    },
  664}
  665
  666impl EditPredictionPreview {
  667    pub fn released_too_fast(&self) -> bool {
  668        match self {
  669            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  670            EditPredictionPreview::Active { .. } => false,
  671        }
  672    }
  673
  674    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  675        if let EditPredictionPreview::Active {
  676            previous_scroll_position,
  677            ..
  678        } = self
  679        {
  680            *previous_scroll_position = scroll_position;
  681        }
  682    }
  683}
  684
  685pub struct ContextMenuOptions {
  686    pub min_entries_visible: usize,
  687    pub max_entries_visible: usize,
  688    pub placement: Option<ContextMenuPlacement>,
  689}
  690
  691#[derive(Debug, Clone, PartialEq, Eq)]
  692pub enum ContextMenuPlacement {
  693    Above,
  694    Below,
  695}
  696
  697#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  698struct EditorActionId(usize);
  699
  700impl EditorActionId {
  701    pub fn post_inc(&mut self) -> Self {
  702        let answer = self.0;
  703
  704        *self = Self(answer + 1);
  705
  706        Self(answer)
  707    }
  708}
  709
  710// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  711// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  712
  713type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  714type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  715
  716#[derive(Default)]
  717struct ScrollbarMarkerState {
  718    scrollbar_size: Size<Pixels>,
  719    dirty: bool,
  720    markers: Arc<[PaintQuad]>,
  721    pending_refresh: Option<Task<Result<()>>>,
  722}
  723
  724impl ScrollbarMarkerState {
  725    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  726        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  727    }
  728}
  729
  730#[derive(Clone, Copy, PartialEq, Eq)]
  731pub enum MinimapVisibility {
  732    Disabled,
  733    Enabled {
  734        /// The configuration currently present in the users settings.
  735        setting_configuration: bool,
  736        /// Whether to override the currently set visibility from the users setting.
  737        toggle_override: bool,
  738    },
  739}
  740
  741impl MinimapVisibility {
  742    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  743        if mode.is_full() {
  744            Self::Enabled {
  745                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  746                toggle_override: false,
  747            }
  748        } else {
  749            Self::Disabled
  750        }
  751    }
  752
  753    fn hidden(&self) -> Self {
  754        match *self {
  755            Self::Enabled {
  756                setting_configuration,
  757                ..
  758            } => Self::Enabled {
  759                setting_configuration,
  760                toggle_override: setting_configuration,
  761            },
  762            Self::Disabled => Self::Disabled,
  763        }
  764    }
  765
  766    fn disabled(&self) -> bool {
  767        match *self {
  768            Self::Disabled => true,
  769            _ => false,
  770        }
  771    }
  772
  773    fn settings_visibility(&self) -> bool {
  774        match *self {
  775            Self::Enabled {
  776                setting_configuration,
  777                ..
  778            } => setting_configuration,
  779            _ => false,
  780        }
  781    }
  782
  783    fn visible(&self) -> bool {
  784        match *self {
  785            Self::Enabled {
  786                setting_configuration,
  787                toggle_override,
  788            } => setting_configuration ^ toggle_override,
  789            _ => false,
  790        }
  791    }
  792
  793    fn toggle_visibility(&self) -> Self {
  794        match *self {
  795            Self::Enabled {
  796                toggle_override,
  797                setting_configuration,
  798            } => Self::Enabled {
  799                setting_configuration,
  800                toggle_override: !toggle_override,
  801            },
  802            Self::Disabled => Self::Disabled,
  803        }
  804    }
  805}
  806
  807#[derive(Clone, Debug)]
  808struct RunnableTasks {
  809    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  810    offset: multi_buffer::Anchor,
  811    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  812    column: u32,
  813    // Values of all named captures, including those starting with '_'
  814    extra_variables: HashMap<String, String>,
  815    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  816    context_range: Range<BufferOffset>,
  817}
  818
  819impl RunnableTasks {
  820    fn resolve<'a>(
  821        &'a self,
  822        cx: &'a task::TaskContext,
  823    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  824        self.templates.iter().filter_map(|(kind, template)| {
  825            template
  826                .resolve_task(&kind.to_id_base(), cx)
  827                .map(|task| (kind.clone(), task))
  828        })
  829    }
  830}
  831
  832#[derive(Clone)]
  833pub struct ResolvedTasks {
  834    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  835    position: Anchor,
  836}
  837
  838#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  839struct BufferOffset(usize);
  840
  841// Addons allow storing per-editor state in other crates (e.g. Vim)
  842pub trait Addon: 'static {
  843    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  844
  845    fn render_buffer_header_controls(
  846        &self,
  847        _: &ExcerptInfo,
  848        _: &Window,
  849        _: &App,
  850    ) -> Option<AnyElement> {
  851        None
  852    }
  853
  854    fn to_any(&self) -> &dyn std::any::Any;
  855
  856    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  857        None
  858    }
  859}
  860
  861struct ChangeLocation {
  862    current: Option<Vec<Anchor>>,
  863    original: Vec<Anchor>,
  864}
  865impl ChangeLocation {
  866    fn locations(&self) -> &[Anchor] {
  867        self.current.as_ref().unwrap_or(&self.original)
  868    }
  869}
  870
  871/// A set of caret positions, registered when the editor was edited.
  872pub struct ChangeList {
  873    changes: Vec<ChangeLocation>,
  874    /// Currently "selected" change.
  875    position: Option<usize>,
  876}
  877
  878impl ChangeList {
  879    pub fn new() -> Self {
  880        Self {
  881            changes: Vec::new(),
  882            position: None,
  883        }
  884    }
  885
  886    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  887    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  888    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  889        if self.changes.is_empty() {
  890            return None;
  891        }
  892
  893        let prev = self.position.unwrap_or(self.changes.len());
  894        let next = if direction == Direction::Prev {
  895            prev.saturating_sub(count)
  896        } else {
  897            (prev + count).min(self.changes.len() - 1)
  898        };
  899        self.position = Some(next);
  900        self.changes.get(next).map(|change| change.locations())
  901    }
  902
  903    /// Adds a new change to the list, resetting the change list position.
  904    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  905        self.position.take();
  906        if let Some(last) = self.changes.last_mut()
  907            && group
  908        {
  909            last.current = Some(new_positions)
  910        } else {
  911            self.changes.push(ChangeLocation {
  912                original: new_positions,
  913                current: None,
  914            });
  915        }
  916    }
  917
  918    pub fn last(&self) -> Option<&[Anchor]> {
  919        self.changes.last().map(|change| change.locations())
  920    }
  921
  922    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  923        self.changes.last().map(|change| change.original.as_slice())
  924    }
  925
  926    pub fn invert_last_group(&mut self) {
  927        if let Some(last) = self.changes.last_mut() {
  928            if let Some(current) = last.current.as_mut() {
  929                mem::swap(&mut last.original, current);
  930            }
  931        }
  932    }
  933}
  934
  935#[derive(Clone)]
  936struct InlineBlamePopoverState {
  937    scroll_handle: ScrollHandle,
  938    commit_message: Option<ParsedCommitMessage>,
  939    markdown: Entity<Markdown>,
  940}
  941
  942struct InlineBlamePopover {
  943    position: gpui::Point<Pixels>,
  944    hide_task: Option<Task<()>>,
  945    popover_bounds: Option<Bounds<Pixels>>,
  946    popover_state: InlineBlamePopoverState,
  947    keyboard_grace: bool,
  948}
  949
  950enum SelectionDragState {
  951    /// State when no drag related activity is detected.
  952    None,
  953    /// State when the mouse is down on a selection that is about to be dragged.
  954    ReadyToDrag {
  955        selection: Selection<Anchor>,
  956        click_position: gpui::Point<Pixels>,
  957        mouse_down_time: Instant,
  958    },
  959    /// State when the mouse is dragging the selection in the editor.
  960    Dragging {
  961        selection: Selection<Anchor>,
  962        drop_cursor: Selection<Anchor>,
  963        hide_drop_cursor: bool,
  964    },
  965}
  966
  967enum ColumnarSelectionState {
  968    FromMouse {
  969        selection_tail: Anchor,
  970        display_point: Option<DisplayPoint>,
  971    },
  972    FromSelection {
  973        selection_tail: Anchor,
  974    },
  975}
  976
  977/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  978/// a breakpoint on them.
  979#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  980struct PhantomBreakpointIndicator {
  981    display_row: DisplayRow,
  982    /// There's a small debounce between hovering over the line and showing the indicator.
  983    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  984    is_active: bool,
  985    collides_with_existing_breakpoint: bool,
  986}
  987
  988/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  989///
  990/// See the [module level documentation](self) for more information.
  991pub struct Editor {
  992    focus_handle: FocusHandle,
  993    last_focused_descendant: Option<WeakFocusHandle>,
  994    /// The text buffer being edited
  995    buffer: Entity<MultiBuffer>,
  996    /// Map of how text in the buffer should be displayed.
  997    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  998    pub display_map: Entity<DisplayMap>,
  999    pub selections: SelectionsCollection,
 1000    pub scroll_manager: ScrollManager,
 1001    /// When inline assist editors are linked, they all render cursors because
 1002    /// typing enters text into each of them, even the ones that aren't focused.
 1003    pub(crate) show_cursor_when_unfocused: bool,
 1004    columnar_selection_state: Option<ColumnarSelectionState>,
 1005    add_selections_state: Option<AddSelectionsState>,
 1006    select_next_state: Option<SelectNextState>,
 1007    select_prev_state: Option<SelectNextState>,
 1008    selection_history: SelectionHistory,
 1009    defer_selection_effects: bool,
 1010    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1011    autoclose_regions: Vec<AutocloseRegion>,
 1012    snippet_stack: InvalidationStack<SnippetState>,
 1013    select_syntax_node_history: SelectSyntaxNodeHistory,
 1014    ime_transaction: Option<TransactionId>,
 1015    pub diagnostics_max_severity: DiagnosticSeverity,
 1016    active_diagnostics: ActiveDiagnostic,
 1017    show_inline_diagnostics: bool,
 1018    inline_diagnostics_update: Task<()>,
 1019    inline_diagnostics_enabled: bool,
 1020    diagnostics_enabled: bool,
 1021    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1022    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1023    hard_wrap: Option<usize>,
 1024
 1025    // TODO: make this a access method
 1026    pub project: Option<Entity<Project>>,
 1027    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1028    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1029    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1030    blink_manager: Entity<BlinkManager>,
 1031    show_cursor_names: bool,
 1032    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1033    pub show_local_selections: bool,
 1034    mode: EditorMode,
 1035    show_breadcrumbs: bool,
 1036    show_gutter: bool,
 1037    show_scrollbars: ScrollbarAxes,
 1038    minimap_visibility: MinimapVisibility,
 1039    offset_content: bool,
 1040    disable_expand_excerpt_buttons: bool,
 1041    show_line_numbers: Option<bool>,
 1042    use_relative_line_numbers: Option<bool>,
 1043    show_git_diff_gutter: Option<bool>,
 1044    show_code_actions: Option<bool>,
 1045    show_runnables: Option<bool>,
 1046    show_breakpoints: Option<bool>,
 1047    show_wrap_guides: Option<bool>,
 1048    show_indent_guides: Option<bool>,
 1049    placeholder_text: Option<Arc<str>>,
 1050    highlight_order: usize,
 1051    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1052    background_highlights: TreeMap<HighlightKey, BackgroundHighlight>,
 1053    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1054    scrollbar_marker_state: ScrollbarMarkerState,
 1055    active_indent_guides_state: ActiveIndentGuidesState,
 1056    nav_history: Option<ItemNavHistory>,
 1057    context_menu: RefCell<Option<CodeContextMenu>>,
 1058    context_menu_options: Option<ContextMenuOptions>,
 1059    mouse_context_menu: Option<MouseContextMenu>,
 1060    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1061    inline_blame_popover: Option<InlineBlamePopover>,
 1062    inline_blame_popover_show_task: Option<Task<()>>,
 1063    signature_help_state: SignatureHelpState,
 1064    auto_signature_help: Option<bool>,
 1065    find_all_references_task_sources: Vec<Anchor>,
 1066    next_completion_id: CompletionId,
 1067    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1068    code_actions_task: Option<Task<Result<()>>>,
 1069    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1070    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1071    document_highlights_task: Option<Task<()>>,
 1072    linked_editing_range_task: Option<Task<Option<()>>>,
 1073    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1074    pending_rename: Option<RenameState>,
 1075    searchable: bool,
 1076    cursor_shape: CursorShape,
 1077    current_line_highlight: Option<CurrentLineHighlight>,
 1078    collapse_matches: bool,
 1079    autoindent_mode: Option<AutoindentMode>,
 1080    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1081    input_enabled: bool,
 1082    use_modal_editing: bool,
 1083    read_only: bool,
 1084    leader_id: Option<CollaboratorId>,
 1085    remote_id: Option<ViewId>,
 1086    pub hover_state: HoverState,
 1087    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1088    gutter_hovered: bool,
 1089    hovered_link_state: Option<HoveredLinkState>,
 1090    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1091    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1092    active_inline_completion: Option<InlineCompletionState>,
 1093    /// Used to prevent flickering as the user types while the menu is open
 1094    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1095    edit_prediction_settings: EditPredictionSettings,
 1096    inline_completions_hidden_for_vim_mode: bool,
 1097    show_inline_completions_override: Option<bool>,
 1098    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1099    edit_prediction_preview: EditPredictionPreview,
 1100    edit_prediction_indent_conflict: bool,
 1101    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1102    inlay_hint_cache: InlayHintCache,
 1103    next_inlay_id: usize,
 1104    _subscriptions: Vec<Subscription>,
 1105    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1106    gutter_dimensions: GutterDimensions,
 1107    style: Option<EditorStyle>,
 1108    text_style_refinement: Option<TextStyleRefinement>,
 1109    next_editor_action_id: EditorActionId,
 1110    editor_actions: Rc<
 1111        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1112    >,
 1113    use_autoclose: bool,
 1114    use_auto_surround: bool,
 1115    auto_replace_emoji_shortcode: bool,
 1116    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1117    show_git_blame_gutter: bool,
 1118    show_git_blame_inline: bool,
 1119    show_git_blame_inline_delay_task: Option<Task<()>>,
 1120    git_blame_inline_enabled: bool,
 1121    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1122    serialize_dirty_buffers: bool,
 1123    show_selection_menu: Option<bool>,
 1124    blame: Option<Entity<GitBlame>>,
 1125    blame_subscription: Option<Subscription>,
 1126    custom_context_menu: Option<
 1127        Box<
 1128            dyn 'static
 1129                + Fn(
 1130                    &mut Self,
 1131                    DisplayPoint,
 1132                    &mut Window,
 1133                    &mut Context<Self>,
 1134                ) -> Option<Entity<ui::ContextMenu>>,
 1135        >,
 1136    >,
 1137    last_bounds: Option<Bounds<Pixels>>,
 1138    last_position_map: Option<Rc<PositionMap>>,
 1139    expect_bounds_change: Option<Bounds<Pixels>>,
 1140    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1141    tasks_update_task: Option<Task<()>>,
 1142    breakpoint_store: Option<Entity<BreakpointStore>>,
 1143    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1144    hovered_diff_hunk_row: Option<DisplayRow>,
 1145    pull_diagnostics_task: Task<()>,
 1146    in_project_search: bool,
 1147    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1148    breadcrumb_header: Option<String>,
 1149    focused_block: Option<FocusedBlock>,
 1150    next_scroll_position: NextScrollCursorCenterTopBottom,
 1151    addons: HashMap<TypeId, Box<dyn Addon>>,
 1152    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1153    load_diff_task: Option<Shared<Task<()>>>,
 1154    /// Whether we are temporarily displaying a diff other than git's
 1155    temporary_diff_override: bool,
 1156    selection_mark_mode: bool,
 1157    toggle_fold_multiple_buffers: Task<()>,
 1158    _scroll_cursor_center_top_bottom_task: Task<()>,
 1159    serialize_selections: Task<()>,
 1160    serialize_folds: Task<()>,
 1161    mouse_cursor_hidden: bool,
 1162    minimap: Option<Entity<Self>>,
 1163    hide_mouse_mode: HideMouseMode,
 1164    pub change_list: ChangeList,
 1165    inline_value_cache: InlineValueCache,
 1166    selection_drag_state: SelectionDragState,
 1167    next_color_inlay_id: usize,
 1168    colors: Option<LspColorData>,
 1169    folding_newlines: Task<()>,
 1170}
 1171
 1172#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1173enum NextScrollCursorCenterTopBottom {
 1174    #[default]
 1175    Center,
 1176    Top,
 1177    Bottom,
 1178}
 1179
 1180impl NextScrollCursorCenterTopBottom {
 1181    fn next(&self) -> Self {
 1182        match self {
 1183            Self::Center => Self::Top,
 1184            Self::Top => Self::Bottom,
 1185            Self::Bottom => Self::Center,
 1186        }
 1187    }
 1188}
 1189
 1190#[derive(Clone)]
 1191pub struct EditorSnapshot {
 1192    pub mode: EditorMode,
 1193    show_gutter: bool,
 1194    show_line_numbers: Option<bool>,
 1195    show_git_diff_gutter: Option<bool>,
 1196    show_code_actions: Option<bool>,
 1197    show_runnables: Option<bool>,
 1198    show_breakpoints: Option<bool>,
 1199    git_blame_gutter_max_author_length: Option<usize>,
 1200    pub display_snapshot: DisplaySnapshot,
 1201    pub placeholder_text: Option<Arc<str>>,
 1202    is_focused: bool,
 1203    scroll_anchor: ScrollAnchor,
 1204    ongoing_scroll: OngoingScroll,
 1205    current_line_highlight: CurrentLineHighlight,
 1206    gutter_hovered: bool,
 1207}
 1208
 1209#[derive(Default, Debug, Clone, Copy)]
 1210pub struct GutterDimensions {
 1211    pub left_padding: Pixels,
 1212    pub right_padding: Pixels,
 1213    pub width: Pixels,
 1214    pub margin: Pixels,
 1215    pub git_blame_entries_width: Option<Pixels>,
 1216}
 1217
 1218impl GutterDimensions {
 1219    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1220        Self {
 1221            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1222            ..Default::default()
 1223        }
 1224    }
 1225
 1226    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1227        -cx.text_system().descent(font_id, font_size)
 1228    }
 1229    /// The full width of the space taken up by the gutter.
 1230    pub fn full_width(&self) -> Pixels {
 1231        self.margin + self.width
 1232    }
 1233
 1234    /// The width of the space reserved for the fold indicators,
 1235    /// use alongside 'justify_end' and `gutter_width` to
 1236    /// right align content with the line numbers
 1237    pub fn fold_area_width(&self) -> Pixels {
 1238        self.margin + self.right_padding
 1239    }
 1240}
 1241
 1242struct CharacterDimensions {
 1243    em_width: Pixels,
 1244    em_advance: Pixels,
 1245    line_height: Pixels,
 1246}
 1247
 1248#[derive(Debug)]
 1249pub struct RemoteSelection {
 1250    pub replica_id: ReplicaId,
 1251    pub selection: Selection<Anchor>,
 1252    pub cursor_shape: CursorShape,
 1253    pub collaborator_id: CollaboratorId,
 1254    pub line_mode: bool,
 1255    pub user_name: Option<SharedString>,
 1256    pub color: PlayerColor,
 1257}
 1258
 1259#[derive(Clone, Debug)]
 1260struct SelectionHistoryEntry {
 1261    selections: Arc<[Selection<Anchor>]>,
 1262    select_next_state: Option<SelectNextState>,
 1263    select_prev_state: Option<SelectNextState>,
 1264    add_selections_state: Option<AddSelectionsState>,
 1265}
 1266
 1267#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1268enum SelectionHistoryMode {
 1269    Normal,
 1270    Undoing,
 1271    Redoing,
 1272    Skipping,
 1273}
 1274
 1275#[derive(Clone, PartialEq, Eq, Hash)]
 1276struct HoveredCursor {
 1277    replica_id: u16,
 1278    selection_id: usize,
 1279}
 1280
 1281impl Default for SelectionHistoryMode {
 1282    fn default() -> Self {
 1283        Self::Normal
 1284    }
 1285}
 1286
 1287#[derive(Debug)]
 1288/// SelectionEffects controls the side-effects of updating the selection.
 1289///
 1290/// The default behaviour does "what you mostly want":
 1291/// - it pushes to the nav history if the cursor moved by >10 lines
 1292/// - it re-triggers completion requests
 1293/// - it scrolls to fit
 1294///
 1295/// You might want to modify these behaviours. For example when doing a "jump"
 1296/// like go to definition, we always want to add to nav history; but when scrolling
 1297/// in vim mode we never do.
 1298///
 1299/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1300/// move.
 1301#[derive(Clone)]
 1302pub struct SelectionEffects {
 1303    nav_history: Option<bool>,
 1304    completions: bool,
 1305    scroll: Option<Autoscroll>,
 1306}
 1307
 1308impl Default for SelectionEffects {
 1309    fn default() -> Self {
 1310        Self {
 1311            nav_history: None,
 1312            completions: true,
 1313            scroll: Some(Autoscroll::fit()),
 1314        }
 1315    }
 1316}
 1317impl SelectionEffects {
 1318    pub fn scroll(scroll: Autoscroll) -> Self {
 1319        Self {
 1320            scroll: Some(scroll),
 1321            ..Default::default()
 1322        }
 1323    }
 1324
 1325    pub fn no_scroll() -> Self {
 1326        Self {
 1327            scroll: None,
 1328            ..Default::default()
 1329        }
 1330    }
 1331
 1332    pub fn completions(self, completions: bool) -> Self {
 1333        Self {
 1334            completions,
 1335            ..self
 1336        }
 1337    }
 1338
 1339    pub fn nav_history(self, nav_history: bool) -> Self {
 1340        Self {
 1341            nav_history: Some(nav_history),
 1342            ..self
 1343        }
 1344    }
 1345}
 1346
 1347struct DeferredSelectionEffectsState {
 1348    changed: bool,
 1349    effects: SelectionEffects,
 1350    old_cursor_position: Anchor,
 1351    history_entry: SelectionHistoryEntry,
 1352}
 1353
 1354#[derive(Default)]
 1355struct SelectionHistory {
 1356    #[allow(clippy::type_complexity)]
 1357    selections_by_transaction:
 1358        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1359    mode: SelectionHistoryMode,
 1360    undo_stack: VecDeque<SelectionHistoryEntry>,
 1361    redo_stack: VecDeque<SelectionHistoryEntry>,
 1362}
 1363
 1364impl SelectionHistory {
 1365    #[track_caller]
 1366    fn insert_transaction(
 1367        &mut self,
 1368        transaction_id: TransactionId,
 1369        selections: Arc<[Selection<Anchor>]>,
 1370    ) {
 1371        if selections.is_empty() {
 1372            log::error!(
 1373                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1374                std::panic::Location::caller()
 1375            );
 1376            return;
 1377        }
 1378        self.selections_by_transaction
 1379            .insert(transaction_id, (selections, None));
 1380    }
 1381
 1382    #[allow(clippy::type_complexity)]
 1383    fn transaction(
 1384        &self,
 1385        transaction_id: TransactionId,
 1386    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1387        self.selections_by_transaction.get(&transaction_id)
 1388    }
 1389
 1390    #[allow(clippy::type_complexity)]
 1391    fn transaction_mut(
 1392        &mut self,
 1393        transaction_id: TransactionId,
 1394    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1395        self.selections_by_transaction.get_mut(&transaction_id)
 1396    }
 1397
 1398    fn push(&mut self, entry: SelectionHistoryEntry) {
 1399        if !entry.selections.is_empty() {
 1400            match self.mode {
 1401                SelectionHistoryMode::Normal => {
 1402                    self.push_undo(entry);
 1403                    self.redo_stack.clear();
 1404                }
 1405                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1406                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1407                SelectionHistoryMode::Skipping => {}
 1408            }
 1409        }
 1410    }
 1411
 1412    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1413        if self
 1414            .undo_stack
 1415            .back()
 1416            .map_or(true, |e| e.selections != entry.selections)
 1417        {
 1418            self.undo_stack.push_back(entry);
 1419            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1420                self.undo_stack.pop_front();
 1421            }
 1422        }
 1423    }
 1424
 1425    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1426        if self
 1427            .redo_stack
 1428            .back()
 1429            .map_or(true, |e| e.selections != entry.selections)
 1430        {
 1431            self.redo_stack.push_back(entry);
 1432            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1433                self.redo_stack.pop_front();
 1434            }
 1435        }
 1436    }
 1437}
 1438
 1439#[derive(Clone, Copy)]
 1440pub struct RowHighlightOptions {
 1441    pub autoscroll: bool,
 1442    pub include_gutter: bool,
 1443}
 1444
 1445impl Default for RowHighlightOptions {
 1446    fn default() -> Self {
 1447        Self {
 1448            autoscroll: Default::default(),
 1449            include_gutter: true,
 1450        }
 1451    }
 1452}
 1453
 1454struct RowHighlight {
 1455    index: usize,
 1456    range: Range<Anchor>,
 1457    color: Hsla,
 1458    options: RowHighlightOptions,
 1459    type_id: TypeId,
 1460}
 1461
 1462#[derive(Clone, Debug)]
 1463struct AddSelectionsState {
 1464    groups: Vec<AddSelectionsGroup>,
 1465}
 1466
 1467#[derive(Clone, Debug)]
 1468struct AddSelectionsGroup {
 1469    above: bool,
 1470    stack: Vec<usize>,
 1471}
 1472
 1473#[derive(Clone)]
 1474struct SelectNextState {
 1475    query: AhoCorasick,
 1476    wordwise: bool,
 1477    done: bool,
 1478}
 1479
 1480impl std::fmt::Debug for SelectNextState {
 1481    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1482        f.debug_struct(std::any::type_name::<Self>())
 1483            .field("wordwise", &self.wordwise)
 1484            .field("done", &self.done)
 1485            .finish()
 1486    }
 1487}
 1488
 1489#[derive(Debug)]
 1490struct AutocloseRegion {
 1491    selection_id: usize,
 1492    range: Range<Anchor>,
 1493    pair: BracketPair,
 1494}
 1495
 1496#[derive(Debug)]
 1497struct SnippetState {
 1498    ranges: Vec<Vec<Range<Anchor>>>,
 1499    active_index: usize,
 1500    choices: Vec<Option<Vec<String>>>,
 1501}
 1502
 1503#[doc(hidden)]
 1504pub struct RenameState {
 1505    pub range: Range<Anchor>,
 1506    pub old_name: Arc<str>,
 1507    pub editor: Entity<Editor>,
 1508    block_id: CustomBlockId,
 1509}
 1510
 1511struct InvalidationStack<T>(Vec<T>);
 1512
 1513struct RegisteredInlineCompletionProvider {
 1514    provider: Arc<dyn InlineCompletionProviderHandle>,
 1515    _subscription: Subscription,
 1516}
 1517
 1518#[derive(Debug, PartialEq, Eq)]
 1519pub struct ActiveDiagnosticGroup {
 1520    pub active_range: Range<Anchor>,
 1521    pub active_message: String,
 1522    pub group_id: usize,
 1523    pub blocks: HashSet<CustomBlockId>,
 1524}
 1525
 1526#[derive(Debug, PartialEq, Eq)]
 1527
 1528pub(crate) enum ActiveDiagnostic {
 1529    None,
 1530    All,
 1531    Group(ActiveDiagnosticGroup),
 1532}
 1533
 1534#[derive(Serialize, Deserialize, Clone, Debug)]
 1535pub struct ClipboardSelection {
 1536    /// The number of bytes in this selection.
 1537    pub len: usize,
 1538    /// Whether this was a full-line selection.
 1539    pub is_entire_line: bool,
 1540    /// The indentation of the first line when this content was originally copied.
 1541    pub first_line_indent: u32,
 1542}
 1543
 1544// selections, scroll behavior, was newest selection reversed
 1545type SelectSyntaxNodeHistoryState = (
 1546    Box<[Selection<usize>]>,
 1547    SelectSyntaxNodeScrollBehavior,
 1548    bool,
 1549);
 1550
 1551#[derive(Default)]
 1552struct SelectSyntaxNodeHistory {
 1553    stack: Vec<SelectSyntaxNodeHistoryState>,
 1554    // disable temporarily to allow changing selections without losing the stack
 1555    pub disable_clearing: bool,
 1556}
 1557
 1558impl SelectSyntaxNodeHistory {
 1559    pub fn try_clear(&mut self) {
 1560        if !self.disable_clearing {
 1561            self.stack.clear();
 1562        }
 1563    }
 1564
 1565    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1566        self.stack.push(selection);
 1567    }
 1568
 1569    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1570        self.stack.pop()
 1571    }
 1572}
 1573
 1574enum SelectSyntaxNodeScrollBehavior {
 1575    CursorTop,
 1576    FitSelection,
 1577    CursorBottom,
 1578}
 1579
 1580#[derive(Debug)]
 1581pub(crate) struct NavigationData {
 1582    cursor_anchor: Anchor,
 1583    cursor_position: Point,
 1584    scroll_anchor: ScrollAnchor,
 1585    scroll_top_row: u32,
 1586}
 1587
 1588#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1589pub enum GotoDefinitionKind {
 1590    Symbol,
 1591    Declaration,
 1592    Type,
 1593    Implementation,
 1594}
 1595
 1596#[derive(Debug, Clone)]
 1597enum InlayHintRefreshReason {
 1598    ModifiersChanged(bool),
 1599    Toggle(bool),
 1600    SettingsChange(InlayHintSettings),
 1601    NewLinesShown,
 1602    BufferEdited(HashSet<Arc<Language>>),
 1603    RefreshRequested,
 1604    ExcerptsRemoved(Vec<ExcerptId>),
 1605}
 1606
 1607impl InlayHintRefreshReason {
 1608    fn description(&self) -> &'static str {
 1609        match self {
 1610            Self::ModifiersChanged(_) => "modifiers changed",
 1611            Self::Toggle(_) => "toggle",
 1612            Self::SettingsChange(_) => "settings change",
 1613            Self::NewLinesShown => "new lines shown",
 1614            Self::BufferEdited(_) => "buffer edited",
 1615            Self::RefreshRequested => "refresh requested",
 1616            Self::ExcerptsRemoved(_) => "excerpts removed",
 1617        }
 1618    }
 1619}
 1620
 1621pub enum FormatTarget {
 1622    Buffers(HashSet<Entity<Buffer>>),
 1623    Ranges(Vec<Range<MultiBufferPoint>>),
 1624}
 1625
 1626pub(crate) struct FocusedBlock {
 1627    id: BlockId,
 1628    focus_handle: WeakFocusHandle,
 1629}
 1630
 1631#[derive(Clone)]
 1632enum JumpData {
 1633    MultiBufferRow {
 1634        row: MultiBufferRow,
 1635        line_offset_from_top: u32,
 1636    },
 1637    MultiBufferPoint {
 1638        excerpt_id: ExcerptId,
 1639        position: Point,
 1640        anchor: text::Anchor,
 1641        line_offset_from_top: u32,
 1642    },
 1643}
 1644
 1645pub enum MultibufferSelectionMode {
 1646    First,
 1647    All,
 1648}
 1649
 1650#[derive(Clone, Copy, Debug, Default)]
 1651pub struct RewrapOptions {
 1652    pub override_language_settings: bool,
 1653    pub preserve_existing_whitespace: bool,
 1654}
 1655
 1656impl Editor {
 1657    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1658        let buffer = cx.new(|cx| Buffer::local("", cx));
 1659        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1660        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1661    }
 1662
 1663    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1664        let buffer = cx.new(|cx| Buffer::local("", cx));
 1665        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1666        Self::new(EditorMode::full(), buffer, None, window, cx)
 1667    }
 1668
 1669    pub fn auto_height(
 1670        min_lines: usize,
 1671        max_lines: usize,
 1672        window: &mut Window,
 1673        cx: &mut Context<Self>,
 1674    ) -> Self {
 1675        let buffer = cx.new(|cx| Buffer::local("", cx));
 1676        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1677        Self::new(
 1678            EditorMode::AutoHeight {
 1679                min_lines,
 1680                max_lines: Some(max_lines),
 1681            },
 1682            buffer,
 1683            None,
 1684            window,
 1685            cx,
 1686        )
 1687    }
 1688
 1689    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1690    /// The editor grows as tall as needed to fit its content.
 1691    pub fn auto_height_unbounded(
 1692        min_lines: usize,
 1693        window: &mut Window,
 1694        cx: &mut Context<Self>,
 1695    ) -> Self {
 1696        let buffer = cx.new(|cx| Buffer::local("", cx));
 1697        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1698        Self::new(
 1699            EditorMode::AutoHeight {
 1700                min_lines,
 1701                max_lines: None,
 1702            },
 1703            buffer,
 1704            None,
 1705            window,
 1706            cx,
 1707        )
 1708    }
 1709
 1710    pub fn for_buffer(
 1711        buffer: Entity<Buffer>,
 1712        project: Option<Entity<Project>>,
 1713        window: &mut Window,
 1714        cx: &mut Context<Self>,
 1715    ) -> Self {
 1716        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1717        Self::new(EditorMode::full(), buffer, project, window, cx)
 1718    }
 1719
 1720    pub fn for_multibuffer(
 1721        buffer: Entity<MultiBuffer>,
 1722        project: Option<Entity<Project>>,
 1723        window: &mut Window,
 1724        cx: &mut Context<Self>,
 1725    ) -> Self {
 1726        Self::new(EditorMode::full(), buffer, project, window, cx)
 1727    }
 1728
 1729    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1730        let mut clone = Self::new(
 1731            self.mode.clone(),
 1732            self.buffer.clone(),
 1733            self.project.clone(),
 1734            window,
 1735            cx,
 1736        );
 1737        self.display_map.update(cx, |display_map, cx| {
 1738            let snapshot = display_map.snapshot(cx);
 1739            clone.display_map.update(cx, |display_map, cx| {
 1740                display_map.set_state(&snapshot, cx);
 1741            });
 1742        });
 1743        clone.folds_did_change(cx);
 1744        clone.selections.clone_state(&self.selections);
 1745        clone.scroll_manager.clone_state(&self.scroll_manager);
 1746        clone.searchable = self.searchable;
 1747        clone.read_only = self.read_only;
 1748        clone
 1749    }
 1750
 1751    pub fn new(
 1752        mode: EditorMode,
 1753        buffer: Entity<MultiBuffer>,
 1754        project: Option<Entity<Project>>,
 1755        window: &mut Window,
 1756        cx: &mut Context<Self>,
 1757    ) -> Self {
 1758        Editor::new_internal(mode, buffer, project, None, window, cx)
 1759    }
 1760
 1761    fn new_internal(
 1762        mode: EditorMode,
 1763        buffer: Entity<MultiBuffer>,
 1764        project: Option<Entity<Project>>,
 1765        display_map: Option<Entity<DisplayMap>>,
 1766        window: &mut Window,
 1767        cx: &mut Context<Self>,
 1768    ) -> Self {
 1769        debug_assert!(
 1770            display_map.is_none() || mode.is_minimap(),
 1771            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1772        );
 1773
 1774        let full_mode = mode.is_full();
 1775        let is_minimap = mode.is_minimap();
 1776        let diagnostics_max_severity = if full_mode {
 1777            EditorSettings::get_global(cx)
 1778                .diagnostics_max_severity
 1779                .unwrap_or(DiagnosticSeverity::Hint)
 1780        } else {
 1781            DiagnosticSeverity::Off
 1782        };
 1783        let style = window.text_style();
 1784        let font_size = style.font_size.to_pixels(window.rem_size());
 1785        let editor = cx.entity().downgrade();
 1786        let fold_placeholder = FoldPlaceholder {
 1787            constrain_width: true,
 1788            render: Arc::new(move |fold_id, fold_range, cx| {
 1789                let editor = editor.clone();
 1790                div()
 1791                    .id(fold_id)
 1792                    .bg(cx.theme().colors().ghost_element_background)
 1793                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1794                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1795                    .rounded_xs()
 1796                    .size_full()
 1797                    .cursor_pointer()
 1798                    .child("")
 1799                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1800                    .on_click(move |_, _window, cx| {
 1801                        editor
 1802                            .update(cx, |editor, cx| {
 1803                                editor.unfold_ranges(
 1804                                    &[fold_range.start..fold_range.end],
 1805                                    true,
 1806                                    false,
 1807                                    cx,
 1808                                );
 1809                                cx.stop_propagation();
 1810                            })
 1811                            .ok();
 1812                    })
 1813                    .into_any()
 1814            }),
 1815            merge_adjacent: true,
 1816            ..FoldPlaceholder::default()
 1817        };
 1818        let display_map = display_map.unwrap_or_else(|| {
 1819            cx.new(|cx| {
 1820                DisplayMap::new(
 1821                    buffer.clone(),
 1822                    style.font(),
 1823                    font_size,
 1824                    None,
 1825                    FILE_HEADER_HEIGHT,
 1826                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1827                    fold_placeholder,
 1828                    diagnostics_max_severity,
 1829                    cx,
 1830                )
 1831            })
 1832        });
 1833
 1834        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1835
 1836        let blink_manager = cx.new(|cx| {
 1837            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1838            if is_minimap {
 1839                blink_manager.disable(cx);
 1840            }
 1841            blink_manager
 1842        });
 1843
 1844        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1845            .then(|| language_settings::SoftWrap::None);
 1846
 1847        let mut project_subscriptions = Vec::new();
 1848        if full_mode {
 1849            if let Some(project) = project.as_ref() {
 1850                project_subscriptions.push(cx.subscribe_in(
 1851                    project,
 1852                    window,
 1853                    |editor, _, event, window, cx| match event {
 1854                        project::Event::RefreshCodeLens => {
 1855                            // we always query lens with actions, without storing them, always refreshing them
 1856                        }
 1857                        project::Event::RefreshInlayHints => {
 1858                            editor
 1859                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1860                        }
 1861                        project::Event::LanguageServerAdded(..)
 1862                        | project::Event::LanguageServerRemoved(..) => {
 1863                            if editor.tasks_update_task.is_none() {
 1864                                editor.tasks_update_task =
 1865                                    Some(editor.refresh_runnables(window, cx));
 1866                            }
 1867                            editor.update_lsp_data(true, None, window, cx);
 1868                        }
 1869                        project::Event::SnippetEdit(id, snippet_edits) => {
 1870                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1871                                let focus_handle = editor.focus_handle(cx);
 1872                                if focus_handle.is_focused(window) {
 1873                                    let snapshot = buffer.read(cx).snapshot();
 1874                                    for (range, snippet) in snippet_edits {
 1875                                        let editor_range =
 1876                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1877                                        editor
 1878                                            .insert_snippet(
 1879                                                &[editor_range],
 1880                                                snippet.clone(),
 1881                                                window,
 1882                                                cx,
 1883                                            )
 1884                                            .ok();
 1885                                    }
 1886                                }
 1887                            }
 1888                        }
 1889                        _ => {}
 1890                    },
 1891                ));
 1892                if let Some(task_inventory) = project
 1893                    .read(cx)
 1894                    .task_store()
 1895                    .read(cx)
 1896                    .task_inventory()
 1897                    .cloned()
 1898                {
 1899                    project_subscriptions.push(cx.observe_in(
 1900                        &task_inventory,
 1901                        window,
 1902                        |editor, _, window, cx| {
 1903                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1904                        },
 1905                    ));
 1906                };
 1907
 1908                project_subscriptions.push(cx.subscribe_in(
 1909                    &project.read(cx).breakpoint_store(),
 1910                    window,
 1911                    |editor, _, event, window, cx| match event {
 1912                        BreakpointStoreEvent::ClearDebugLines => {
 1913                            editor.clear_row_highlights::<ActiveDebugLine>();
 1914                            editor.refresh_inline_values(cx);
 1915                        }
 1916                        BreakpointStoreEvent::SetDebugLine => {
 1917                            if editor.go_to_active_debug_line(window, cx) {
 1918                                cx.stop_propagation();
 1919                            }
 1920
 1921                            editor.refresh_inline_values(cx);
 1922                        }
 1923                        _ => {}
 1924                    },
 1925                ));
 1926                let git_store = project.read(cx).git_store().clone();
 1927                let project = project.clone();
 1928                project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1929                    match event {
 1930                        GitStoreEvent::RepositoryUpdated(
 1931                            _,
 1932                            RepositoryEvent::Updated {
 1933                                new_instance: true, ..
 1934                            },
 1935                            _,
 1936                        ) => {
 1937                            this.load_diff_task = Some(
 1938                                update_uncommitted_diff_for_buffer(
 1939                                    cx.entity(),
 1940                                    &project,
 1941                                    this.buffer.read(cx).all_buffers(),
 1942                                    this.buffer.clone(),
 1943                                    cx,
 1944                                )
 1945                                .shared(),
 1946                            );
 1947                        }
 1948                        _ => {}
 1949                    }
 1950                }));
 1951            }
 1952        }
 1953
 1954        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1955
 1956        let inlay_hint_settings =
 1957            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1958        let focus_handle = cx.focus_handle();
 1959        if !is_minimap {
 1960            cx.on_focus(&focus_handle, window, Self::handle_focus)
 1961                .detach();
 1962            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1963                .detach();
 1964            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1965                .detach();
 1966            cx.on_blur(&focus_handle, window, Self::handle_blur)
 1967                .detach();
 1968            cx.observe_pending_input(window, Self::observe_pending_input)
 1969                .detach();
 1970        }
 1971
 1972        let show_indent_guides = if matches!(
 1973            mode,
 1974            EditorMode::SingleLine { .. } | EditorMode::Minimap { .. }
 1975        ) {
 1976            Some(false)
 1977        } else {
 1978            None
 1979        };
 1980
 1981        let breakpoint_store = match (&mode, project.as_ref()) {
 1982            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1983            _ => None,
 1984        };
 1985
 1986        let mut code_action_providers = Vec::new();
 1987        let mut load_uncommitted_diff = None;
 1988        if let Some(project) = project.clone() {
 1989            load_uncommitted_diff = Some(
 1990                update_uncommitted_diff_for_buffer(
 1991                    cx.entity(),
 1992                    &project,
 1993                    buffer.read(cx).all_buffers(),
 1994                    buffer.clone(),
 1995                    cx,
 1996                )
 1997                .shared(),
 1998            );
 1999            code_action_providers.push(Rc::new(project) as Rc<_>);
 2000        }
 2001
 2002        let mut editor = Self {
 2003            focus_handle,
 2004            show_cursor_when_unfocused: false,
 2005            last_focused_descendant: None,
 2006            buffer: buffer.clone(),
 2007            display_map: display_map.clone(),
 2008            selections,
 2009            scroll_manager: ScrollManager::new(cx),
 2010            columnar_selection_state: None,
 2011            add_selections_state: None,
 2012            select_next_state: None,
 2013            select_prev_state: None,
 2014            selection_history: SelectionHistory::default(),
 2015            defer_selection_effects: false,
 2016            deferred_selection_effects_state: None,
 2017            autoclose_regions: Vec::new(),
 2018            snippet_stack: InvalidationStack::default(),
 2019            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2020            ime_transaction: None,
 2021            active_diagnostics: ActiveDiagnostic::None,
 2022            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2023            inline_diagnostics_update: Task::ready(()),
 2024            inline_diagnostics: Vec::new(),
 2025            soft_wrap_mode_override,
 2026            diagnostics_max_severity,
 2027            hard_wrap: None,
 2028            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2029            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2030            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2031            project,
 2032            blink_manager: blink_manager.clone(),
 2033            show_local_selections: true,
 2034            show_scrollbars: ScrollbarAxes {
 2035                horizontal: full_mode,
 2036                vertical: full_mode,
 2037            },
 2038            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2039            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 2040            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2041            show_gutter: full_mode,
 2042            show_line_numbers: (!full_mode).then_some(false),
 2043            use_relative_line_numbers: None,
 2044            disable_expand_excerpt_buttons: !full_mode,
 2045            show_git_diff_gutter: None,
 2046            show_code_actions: None,
 2047            show_runnables: None,
 2048            show_breakpoints: None,
 2049            show_wrap_guides: None,
 2050            show_indent_guides,
 2051            placeholder_text: None,
 2052            highlight_order: 0,
 2053            highlighted_rows: HashMap::default(),
 2054            background_highlights: TreeMap::default(),
 2055            gutter_highlights: TreeMap::default(),
 2056            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2057            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2058            nav_history: None,
 2059            context_menu: RefCell::new(None),
 2060            context_menu_options: None,
 2061            mouse_context_menu: None,
 2062            completion_tasks: Vec::new(),
 2063            inline_blame_popover: None,
 2064            inline_blame_popover_show_task: None,
 2065            signature_help_state: SignatureHelpState::default(),
 2066            auto_signature_help: None,
 2067            find_all_references_task_sources: Vec::new(),
 2068            next_completion_id: 0,
 2069            next_inlay_id: 0,
 2070            code_action_providers,
 2071            available_code_actions: None,
 2072            code_actions_task: None,
 2073            quick_selection_highlight_task: None,
 2074            debounced_selection_highlight_task: None,
 2075            document_highlights_task: None,
 2076            linked_editing_range_task: None,
 2077            pending_rename: None,
 2078            searchable: !is_minimap,
 2079            cursor_shape: EditorSettings::get_global(cx)
 2080                .cursor_shape
 2081                .unwrap_or_default(),
 2082            current_line_highlight: None,
 2083            autoindent_mode: Some(AutoindentMode::EachLine),
 2084            collapse_matches: false,
 2085            workspace: None,
 2086            input_enabled: !is_minimap,
 2087            use_modal_editing: full_mode,
 2088            read_only: is_minimap,
 2089            use_autoclose: true,
 2090            use_auto_surround: true,
 2091            auto_replace_emoji_shortcode: false,
 2092            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2093            leader_id: None,
 2094            remote_id: None,
 2095            hover_state: HoverState::default(),
 2096            pending_mouse_down: None,
 2097            hovered_link_state: None,
 2098            edit_prediction_provider: None,
 2099            active_inline_completion: None,
 2100            stale_inline_completion_in_menu: None,
 2101            edit_prediction_preview: EditPredictionPreview::Inactive {
 2102                released_too_fast: false,
 2103            },
 2104            inline_diagnostics_enabled: full_mode,
 2105            diagnostics_enabled: full_mode,
 2106            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2107            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2108            gutter_hovered: false,
 2109            pixel_position_of_newest_cursor: None,
 2110            last_bounds: None,
 2111            last_position_map: None,
 2112            expect_bounds_change: None,
 2113            gutter_dimensions: GutterDimensions::default(),
 2114            style: None,
 2115            show_cursor_names: false,
 2116            hovered_cursors: HashMap::default(),
 2117            next_editor_action_id: EditorActionId::default(),
 2118            editor_actions: Rc::default(),
 2119            inline_completions_hidden_for_vim_mode: false,
 2120            show_inline_completions_override: None,
 2121            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 2122            edit_prediction_settings: EditPredictionSettings::Disabled,
 2123            edit_prediction_indent_conflict: false,
 2124            edit_prediction_requires_modifier_in_indent_conflict: true,
 2125            custom_context_menu: None,
 2126            show_git_blame_gutter: false,
 2127            show_git_blame_inline: false,
 2128            show_selection_menu: None,
 2129            show_git_blame_inline_delay_task: None,
 2130            git_blame_inline_enabled: full_mode
 2131                && ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2132            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2133            serialize_dirty_buffers: !is_minimap
 2134                && ProjectSettings::get_global(cx)
 2135                    .session
 2136                    .restore_unsaved_buffers,
 2137            blame: None,
 2138            blame_subscription: None,
 2139            tasks: BTreeMap::default(),
 2140
 2141            breakpoint_store,
 2142            gutter_breakpoint_indicator: (None, None),
 2143            hovered_diff_hunk_row: None,
 2144            _subscriptions: (!is_minimap)
 2145                .then(|| {
 2146                    vec![
 2147                        cx.observe(&buffer, Self::on_buffer_changed),
 2148                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2149                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2150                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2151                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2152                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2153                        cx.observe_window_activation(window, |editor, window, cx| {
 2154                            let active = window.is_window_active();
 2155                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2156                                if active {
 2157                                    blink_manager.enable(cx);
 2158                                } else {
 2159                                    blink_manager.disable(cx);
 2160                                }
 2161                            });
 2162                            if active {
 2163                                editor.show_mouse_cursor(cx);
 2164                            }
 2165                        }),
 2166                    ]
 2167                })
 2168                .unwrap_or_default(),
 2169            tasks_update_task: None,
 2170            pull_diagnostics_task: Task::ready(()),
 2171            colors: None,
 2172            next_color_inlay_id: 0,
 2173            linked_edit_ranges: Default::default(),
 2174            in_project_search: false,
 2175            previous_search_ranges: None,
 2176            breadcrumb_header: None,
 2177            focused_block: None,
 2178            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2179            addons: HashMap::default(),
 2180            registered_buffers: HashMap::default(),
 2181            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2182            selection_mark_mode: false,
 2183            toggle_fold_multiple_buffers: Task::ready(()),
 2184            serialize_selections: Task::ready(()),
 2185            serialize_folds: Task::ready(()),
 2186            text_style_refinement: None,
 2187            load_diff_task: load_uncommitted_diff,
 2188            temporary_diff_override: false,
 2189            mouse_cursor_hidden: false,
 2190            minimap: None,
 2191            hide_mouse_mode: EditorSettings::get_global(cx)
 2192                .hide_mouse
 2193                .unwrap_or_default(),
 2194            change_list: ChangeList::new(),
 2195            mode,
 2196            selection_drag_state: SelectionDragState::None,
 2197            folding_newlines: Task::ready(()),
 2198        };
 2199
 2200        if is_minimap {
 2201            return editor;
 2202        }
 2203
 2204        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2205            editor
 2206                ._subscriptions
 2207                .push(cx.observe(breakpoints, |_, _, cx| {
 2208                    cx.notify();
 2209                }));
 2210        }
 2211        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2212        editor._subscriptions.extend(project_subscriptions);
 2213
 2214        editor._subscriptions.push(cx.subscribe_in(
 2215            &cx.entity(),
 2216            window,
 2217            |editor, _, e: &EditorEvent, window, cx| match e {
 2218                EditorEvent::ScrollPositionChanged { local, .. } => {
 2219                    if *local {
 2220                        let new_anchor = editor.scroll_manager.anchor();
 2221                        let snapshot = editor.snapshot(window, cx);
 2222                        editor.update_restoration_data(cx, move |data| {
 2223                            data.scroll_position = (
 2224                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2225                                new_anchor.offset,
 2226                            );
 2227                        });
 2228                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2229                        editor.inline_blame_popover.take();
 2230                    }
 2231                }
 2232                EditorEvent::Edited { .. } => {
 2233                    if !vim_enabled(cx) {
 2234                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2235                        let pop_state = editor
 2236                            .change_list
 2237                            .last()
 2238                            .map(|previous| {
 2239                                previous.len() == selections.len()
 2240                                    && previous.iter().enumerate().all(|(ix, p)| {
 2241                                        p.to_display_point(&map).row()
 2242                                            == selections[ix].head().row()
 2243                                    })
 2244                            })
 2245                            .unwrap_or(false);
 2246                        let new_positions = selections
 2247                            .into_iter()
 2248                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2249                            .collect();
 2250                        editor
 2251                            .change_list
 2252                            .push_to_change_list(pop_state, new_positions);
 2253                    }
 2254                }
 2255                _ => (),
 2256            },
 2257        ));
 2258
 2259        if let Some(dap_store) = editor
 2260            .project
 2261            .as_ref()
 2262            .map(|project| project.read(cx).dap_store())
 2263        {
 2264            let weak_editor = cx.weak_entity();
 2265
 2266            editor
 2267                ._subscriptions
 2268                .push(
 2269                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2270                        let session_entity = cx.entity();
 2271                        weak_editor
 2272                            .update(cx, |editor, cx| {
 2273                                editor._subscriptions.push(
 2274                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2275                                );
 2276                            })
 2277                            .ok();
 2278                    }),
 2279                );
 2280
 2281            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2282                editor
 2283                    ._subscriptions
 2284                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2285            }
 2286        }
 2287
 2288        // skip adding the initial selection to selection history
 2289        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2290        editor.end_selection(window, cx);
 2291        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2292
 2293        editor.scroll_manager.show_scrollbars(window, cx);
 2294        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2295
 2296        if full_mode {
 2297            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2298            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2299
 2300            if editor.git_blame_inline_enabled {
 2301                editor.start_git_blame_inline(false, window, cx);
 2302            }
 2303
 2304            editor.go_to_active_debug_line(window, cx);
 2305
 2306            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2307                if let Some(project) = editor.project.as_ref() {
 2308                    let handle = project.update(cx, |project, cx| {
 2309                        project.register_buffer_with_language_servers(&buffer, cx)
 2310                    });
 2311                    editor
 2312                        .registered_buffers
 2313                        .insert(buffer.read(cx).remote_id(), handle);
 2314                }
 2315            }
 2316
 2317            editor.minimap =
 2318                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2319            editor.colors = Some(LspColorData::new(cx));
 2320            editor.update_lsp_data(false, None, window, cx);
 2321        }
 2322
 2323        if editor.mode.is_full() {
 2324            editor.report_editor_event("Editor Opened", None, cx);
 2325        }
 2326
 2327        editor
 2328    }
 2329
 2330    pub fn deploy_mouse_context_menu(
 2331        &mut self,
 2332        position: gpui::Point<Pixels>,
 2333        context_menu: Entity<ContextMenu>,
 2334        window: &mut Window,
 2335        cx: &mut Context<Self>,
 2336    ) {
 2337        self.mouse_context_menu = Some(MouseContextMenu::new(
 2338            self,
 2339            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2340            context_menu,
 2341            window,
 2342            cx,
 2343        ));
 2344    }
 2345
 2346    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2347        self.mouse_context_menu
 2348            .as_ref()
 2349            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2350    }
 2351
 2352    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2353        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2354    }
 2355
 2356    fn key_context_internal(
 2357        &self,
 2358        has_active_edit_prediction: bool,
 2359        window: &Window,
 2360        cx: &App,
 2361    ) -> KeyContext {
 2362        let mut key_context = KeyContext::new_with_defaults();
 2363        key_context.add("Editor");
 2364        let mode = match self.mode {
 2365            EditorMode::SingleLine { .. } => "single_line",
 2366            EditorMode::AutoHeight { .. } => "auto_height",
 2367            EditorMode::Minimap { .. } => "minimap",
 2368            EditorMode::Full { .. } => "full",
 2369        };
 2370
 2371        if EditorSettings::jupyter_enabled(cx) {
 2372            key_context.add("jupyter");
 2373        }
 2374
 2375        key_context.set("mode", mode);
 2376        if self.pending_rename.is_some() {
 2377            key_context.add("renaming");
 2378        }
 2379
 2380        match self.context_menu.borrow().as_ref() {
 2381            Some(CodeContextMenu::Completions(menu)) => {
 2382                if menu.visible() {
 2383                    key_context.add("menu");
 2384                    key_context.add("showing_completions");
 2385                }
 2386            }
 2387            Some(CodeContextMenu::CodeActions(menu)) => {
 2388                if menu.visible() {
 2389                    key_context.add("menu");
 2390                    key_context.add("showing_code_actions")
 2391                }
 2392            }
 2393            None => {}
 2394        }
 2395
 2396        if self.signature_help_state.has_multiple_signatures() {
 2397            key_context.add("showing_signature_help");
 2398        }
 2399
 2400        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2401        if !self.focus_handle(cx).contains_focused(window, cx)
 2402            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2403        {
 2404            for addon in self.addons.values() {
 2405                addon.extend_key_context(&mut key_context, cx)
 2406            }
 2407        }
 2408
 2409        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2410            if let Some(extension) = singleton_buffer
 2411                .read(cx)
 2412                .file()
 2413                .and_then(|file| file.path().extension()?.to_str())
 2414            {
 2415                key_context.set("extension", extension.to_string());
 2416            }
 2417        } else {
 2418            key_context.add("multibuffer");
 2419        }
 2420
 2421        if has_active_edit_prediction {
 2422            if self.edit_prediction_in_conflict() {
 2423                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2424            } else {
 2425                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2426                key_context.add("copilot_suggestion");
 2427            }
 2428        }
 2429
 2430        if self.selection_mark_mode {
 2431            key_context.add("selection_mode");
 2432        }
 2433
 2434        key_context
 2435    }
 2436
 2437    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2438        if self.mouse_cursor_hidden {
 2439            self.mouse_cursor_hidden = false;
 2440            cx.notify();
 2441        }
 2442    }
 2443
 2444    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2445        let hide_mouse_cursor = match origin {
 2446            HideMouseCursorOrigin::TypingAction => {
 2447                matches!(
 2448                    self.hide_mouse_mode,
 2449                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2450                )
 2451            }
 2452            HideMouseCursorOrigin::MovementAction => {
 2453                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2454            }
 2455        };
 2456        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2457            self.mouse_cursor_hidden = hide_mouse_cursor;
 2458            cx.notify();
 2459        }
 2460    }
 2461
 2462    pub fn edit_prediction_in_conflict(&self) -> bool {
 2463        if !self.show_edit_predictions_in_menu() {
 2464            return false;
 2465        }
 2466
 2467        let showing_completions = self
 2468            .context_menu
 2469            .borrow()
 2470            .as_ref()
 2471            .map_or(false, |context| {
 2472                matches!(context, CodeContextMenu::Completions(_))
 2473            });
 2474
 2475        showing_completions
 2476            || self.edit_prediction_requires_modifier()
 2477            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2478            // bindings to insert tab characters.
 2479            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2480    }
 2481
 2482    pub fn accept_edit_prediction_keybind(
 2483        &self,
 2484        accept_partial: bool,
 2485        window: &Window,
 2486        cx: &App,
 2487    ) -> AcceptEditPredictionBinding {
 2488        let key_context = self.key_context_internal(true, window, cx);
 2489        let in_conflict = self.edit_prediction_in_conflict();
 2490
 2491        let bindings = if accept_partial {
 2492            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2493        } else {
 2494            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2495        };
 2496
 2497        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2498        // just the first one.
 2499        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2500            !in_conflict
 2501                || binding
 2502                    .keystrokes()
 2503                    .first()
 2504                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2505        }))
 2506    }
 2507
 2508    pub fn new_file(
 2509        workspace: &mut Workspace,
 2510        _: &workspace::NewFile,
 2511        window: &mut Window,
 2512        cx: &mut Context<Workspace>,
 2513    ) {
 2514        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2515            "Failed to create buffer",
 2516            window,
 2517            cx,
 2518            |e, _, _| match e.error_code() {
 2519                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2520                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2521                e.error_tag("required").unwrap_or("the latest version")
 2522            )),
 2523                _ => None,
 2524            },
 2525        );
 2526    }
 2527
 2528    pub fn new_in_workspace(
 2529        workspace: &mut Workspace,
 2530        window: &mut Window,
 2531        cx: &mut Context<Workspace>,
 2532    ) -> Task<Result<Entity<Editor>>> {
 2533        let project = workspace.project().clone();
 2534        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2535
 2536        cx.spawn_in(window, async move |workspace, cx| {
 2537            let buffer = create.await?;
 2538            workspace.update_in(cx, |workspace, window, cx| {
 2539                let editor =
 2540                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2541                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2542                editor
 2543            })
 2544        })
 2545    }
 2546
 2547    fn new_file_vertical(
 2548        workspace: &mut Workspace,
 2549        _: &workspace::NewFileSplitVertical,
 2550        window: &mut Window,
 2551        cx: &mut Context<Workspace>,
 2552    ) {
 2553        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2554    }
 2555
 2556    fn new_file_horizontal(
 2557        workspace: &mut Workspace,
 2558        _: &workspace::NewFileSplitHorizontal,
 2559        window: &mut Window,
 2560        cx: &mut Context<Workspace>,
 2561    ) {
 2562        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2563    }
 2564
 2565    fn new_file_in_direction(
 2566        workspace: &mut Workspace,
 2567        direction: SplitDirection,
 2568        window: &mut Window,
 2569        cx: &mut Context<Workspace>,
 2570    ) {
 2571        let project = workspace.project().clone();
 2572        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2573
 2574        cx.spawn_in(window, async move |workspace, cx| {
 2575            let buffer = create.await?;
 2576            workspace.update_in(cx, move |workspace, window, cx| {
 2577                workspace.split_item(
 2578                    direction,
 2579                    Box::new(
 2580                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2581                    ),
 2582                    window,
 2583                    cx,
 2584                )
 2585            })?;
 2586            anyhow::Ok(())
 2587        })
 2588        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2589            match e.error_code() {
 2590                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2591                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2592                e.error_tag("required").unwrap_or("the latest version")
 2593            )),
 2594                _ => None,
 2595            }
 2596        });
 2597    }
 2598
 2599    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2600        self.leader_id
 2601    }
 2602
 2603    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2604        &self.buffer
 2605    }
 2606
 2607    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2608        self.workspace.as_ref()?.0.upgrade()
 2609    }
 2610
 2611    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2612        self.buffer().read(cx).title(cx)
 2613    }
 2614
 2615    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2616        let git_blame_gutter_max_author_length = self
 2617            .render_git_blame_gutter(cx)
 2618            .then(|| {
 2619                if let Some(blame) = self.blame.as_ref() {
 2620                    let max_author_length =
 2621                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2622                    Some(max_author_length)
 2623                } else {
 2624                    None
 2625                }
 2626            })
 2627            .flatten();
 2628
 2629        EditorSnapshot {
 2630            mode: self.mode.clone(),
 2631            show_gutter: self.show_gutter,
 2632            show_line_numbers: self.show_line_numbers,
 2633            show_git_diff_gutter: self.show_git_diff_gutter,
 2634            show_code_actions: self.show_code_actions,
 2635            show_runnables: self.show_runnables,
 2636            show_breakpoints: self.show_breakpoints,
 2637            git_blame_gutter_max_author_length,
 2638            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2639            scroll_anchor: self.scroll_manager.anchor(),
 2640            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2641            placeholder_text: self.placeholder_text.clone(),
 2642            is_focused: self.focus_handle.is_focused(window),
 2643            current_line_highlight: self
 2644                .current_line_highlight
 2645                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2646            gutter_hovered: self.gutter_hovered,
 2647        }
 2648    }
 2649
 2650    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2651        self.buffer.read(cx).language_at(point, cx)
 2652    }
 2653
 2654    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2655        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2656    }
 2657
 2658    pub fn active_excerpt(
 2659        &self,
 2660        cx: &App,
 2661    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2662        self.buffer
 2663            .read(cx)
 2664            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2665    }
 2666
 2667    pub fn mode(&self) -> &EditorMode {
 2668        &self.mode
 2669    }
 2670
 2671    pub fn set_mode(&mut self, mode: EditorMode) {
 2672        self.mode = mode;
 2673    }
 2674
 2675    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2676        self.collaboration_hub.as_deref()
 2677    }
 2678
 2679    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2680        self.collaboration_hub = Some(hub);
 2681    }
 2682
 2683    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2684        self.in_project_search = in_project_search;
 2685    }
 2686
 2687    pub fn set_custom_context_menu(
 2688        &mut self,
 2689        f: impl 'static
 2690        + Fn(
 2691            &mut Self,
 2692            DisplayPoint,
 2693            &mut Window,
 2694            &mut Context<Self>,
 2695        ) -> Option<Entity<ui::ContextMenu>>,
 2696    ) {
 2697        self.custom_context_menu = Some(Box::new(f))
 2698    }
 2699
 2700    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2701        self.completion_provider = provider;
 2702    }
 2703
 2704    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2705        self.semantics_provider.clone()
 2706    }
 2707
 2708    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2709        self.semantics_provider = provider;
 2710    }
 2711
 2712    pub fn set_edit_prediction_provider<T>(
 2713        &mut self,
 2714        provider: Option<Entity<T>>,
 2715        window: &mut Window,
 2716        cx: &mut Context<Self>,
 2717    ) where
 2718        T: EditPredictionProvider,
 2719    {
 2720        self.edit_prediction_provider =
 2721            provider.map(|provider| RegisteredInlineCompletionProvider {
 2722                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2723                    if this.focus_handle.is_focused(window) {
 2724                        this.update_visible_inline_completion(window, cx);
 2725                    }
 2726                }),
 2727                provider: Arc::new(provider),
 2728            });
 2729        self.update_edit_prediction_settings(cx);
 2730        self.refresh_inline_completion(false, false, window, cx);
 2731    }
 2732
 2733    pub fn placeholder_text(&self) -> Option<&str> {
 2734        self.placeholder_text.as_deref()
 2735    }
 2736
 2737    pub fn set_placeholder_text(
 2738        &mut self,
 2739        placeholder_text: impl Into<Arc<str>>,
 2740        cx: &mut Context<Self>,
 2741    ) {
 2742        let placeholder_text = Some(placeholder_text.into());
 2743        if self.placeholder_text != placeholder_text {
 2744            self.placeholder_text = placeholder_text;
 2745            cx.notify();
 2746        }
 2747    }
 2748
 2749    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2750        self.cursor_shape = cursor_shape;
 2751
 2752        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2753        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2754
 2755        cx.notify();
 2756    }
 2757
 2758    pub fn set_current_line_highlight(
 2759        &mut self,
 2760        current_line_highlight: Option<CurrentLineHighlight>,
 2761    ) {
 2762        self.current_line_highlight = current_line_highlight;
 2763    }
 2764
 2765    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2766        self.collapse_matches = collapse_matches;
 2767    }
 2768
 2769    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2770        let buffers = self.buffer.read(cx).all_buffers();
 2771        let Some(project) = self.project.as_ref() else {
 2772            return;
 2773        };
 2774        project.update(cx, |project, cx| {
 2775            for buffer in buffers {
 2776                self.registered_buffers
 2777                    .entry(buffer.read(cx).remote_id())
 2778                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2779            }
 2780        })
 2781    }
 2782
 2783    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2784        if self.collapse_matches {
 2785            return range.start..range.start;
 2786        }
 2787        range.clone()
 2788    }
 2789
 2790    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2791        if self.display_map.read(cx).clip_at_line_ends != clip {
 2792            self.display_map
 2793                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2794        }
 2795    }
 2796
 2797    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2798        self.input_enabled = input_enabled;
 2799    }
 2800
 2801    pub fn set_inline_completions_hidden_for_vim_mode(
 2802        &mut self,
 2803        hidden: bool,
 2804        window: &mut Window,
 2805        cx: &mut Context<Self>,
 2806    ) {
 2807        if hidden != self.inline_completions_hidden_for_vim_mode {
 2808            self.inline_completions_hidden_for_vim_mode = hidden;
 2809            if hidden {
 2810                self.update_visible_inline_completion(window, cx);
 2811            } else {
 2812                self.refresh_inline_completion(true, false, window, cx);
 2813            }
 2814        }
 2815    }
 2816
 2817    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2818        self.menu_inline_completions_policy = value;
 2819    }
 2820
 2821    pub fn set_autoindent(&mut self, autoindent: bool) {
 2822        if autoindent {
 2823            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2824        } else {
 2825            self.autoindent_mode = None;
 2826        }
 2827    }
 2828
 2829    pub fn read_only(&self, cx: &App) -> bool {
 2830        self.read_only || self.buffer.read(cx).read_only()
 2831    }
 2832
 2833    pub fn set_read_only(&mut self, read_only: bool) {
 2834        self.read_only = read_only;
 2835    }
 2836
 2837    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2838        self.use_autoclose = autoclose;
 2839    }
 2840
 2841    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2842        self.use_auto_surround = auto_surround;
 2843    }
 2844
 2845    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2846        self.auto_replace_emoji_shortcode = auto_replace;
 2847    }
 2848
 2849    pub fn toggle_edit_predictions(
 2850        &mut self,
 2851        _: &ToggleEditPrediction,
 2852        window: &mut Window,
 2853        cx: &mut Context<Self>,
 2854    ) {
 2855        if self.show_inline_completions_override.is_some() {
 2856            self.set_show_edit_predictions(None, window, cx);
 2857        } else {
 2858            let show_edit_predictions = !self.edit_predictions_enabled();
 2859            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2860        }
 2861    }
 2862
 2863    pub fn set_show_edit_predictions(
 2864        &mut self,
 2865        show_edit_predictions: Option<bool>,
 2866        window: &mut Window,
 2867        cx: &mut Context<Self>,
 2868    ) {
 2869        self.show_inline_completions_override = show_edit_predictions;
 2870        self.update_edit_prediction_settings(cx);
 2871
 2872        if let Some(false) = show_edit_predictions {
 2873            self.discard_inline_completion(false, cx);
 2874        } else {
 2875            self.refresh_inline_completion(false, true, window, cx);
 2876        }
 2877    }
 2878
 2879    fn inline_completions_disabled_in_scope(
 2880        &self,
 2881        buffer: &Entity<Buffer>,
 2882        buffer_position: language::Anchor,
 2883        cx: &App,
 2884    ) -> bool {
 2885        let snapshot = buffer.read(cx).snapshot();
 2886        let settings = snapshot.settings_at(buffer_position, cx);
 2887
 2888        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2889            return false;
 2890        };
 2891
 2892        scope.override_name().map_or(false, |scope_name| {
 2893            settings
 2894                .edit_predictions_disabled_in
 2895                .iter()
 2896                .any(|s| s == scope_name)
 2897        })
 2898    }
 2899
 2900    pub fn set_use_modal_editing(&mut self, to: bool) {
 2901        self.use_modal_editing = to;
 2902    }
 2903
 2904    pub fn use_modal_editing(&self) -> bool {
 2905        self.use_modal_editing
 2906    }
 2907
 2908    fn selections_did_change(
 2909        &mut self,
 2910        local: bool,
 2911        old_cursor_position: &Anchor,
 2912        effects: SelectionEffects,
 2913        window: &mut Window,
 2914        cx: &mut Context<Self>,
 2915    ) {
 2916        window.invalidate_character_coordinates();
 2917
 2918        // Copy selections to primary selection buffer
 2919        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2920        if local {
 2921            let selections = self.selections.all::<usize>(cx);
 2922            let buffer_handle = self.buffer.read(cx).read(cx);
 2923
 2924            let mut text = String::new();
 2925            for (index, selection) in selections.iter().enumerate() {
 2926                let text_for_selection = buffer_handle
 2927                    .text_for_range(selection.start..selection.end)
 2928                    .collect::<String>();
 2929
 2930                text.push_str(&text_for_selection);
 2931                if index != selections.len() - 1 {
 2932                    text.push('\n');
 2933                }
 2934            }
 2935
 2936            if !text.is_empty() {
 2937                cx.write_to_primary(ClipboardItem::new_string(text));
 2938            }
 2939        }
 2940
 2941        let selection_anchors = self.selections.disjoint_anchors();
 2942
 2943        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2944            self.buffer.update(cx, |buffer, cx| {
 2945                buffer.set_active_selections(
 2946                    &selection_anchors,
 2947                    self.selections.line_mode,
 2948                    self.cursor_shape,
 2949                    cx,
 2950                )
 2951            });
 2952        }
 2953        let display_map = self
 2954            .display_map
 2955            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2956        let buffer = &display_map.buffer_snapshot;
 2957        if self.selections.count() == 1 {
 2958            self.add_selections_state = None;
 2959        }
 2960        self.select_next_state = None;
 2961        self.select_prev_state = None;
 2962        self.select_syntax_node_history.try_clear();
 2963        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 2964        self.snippet_stack.invalidate(&selection_anchors, buffer);
 2965        self.take_rename(false, window, cx);
 2966
 2967        let newest_selection = self.selections.newest_anchor();
 2968        let new_cursor_position = newest_selection.head();
 2969        let selection_start = newest_selection.start;
 2970
 2971        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 2972            self.push_to_nav_history(
 2973                *old_cursor_position,
 2974                Some(new_cursor_position.to_point(buffer)),
 2975                false,
 2976                effects.nav_history == Some(true),
 2977                cx,
 2978            );
 2979        }
 2980
 2981        if local {
 2982            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2983                if !self.registered_buffers.contains_key(&buffer_id) {
 2984                    if let Some(project) = self.project.as_ref() {
 2985                        project.update(cx, |project, cx| {
 2986                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2987                                return;
 2988                            };
 2989                            self.registered_buffers.insert(
 2990                                buffer_id,
 2991                                project.register_buffer_with_language_servers(&buffer, cx),
 2992                            );
 2993                        })
 2994                    }
 2995                }
 2996            }
 2997
 2998            let mut context_menu = self.context_menu.borrow_mut();
 2999            let completion_menu = match context_menu.as_ref() {
 3000                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3001                Some(CodeContextMenu::CodeActions(_)) => {
 3002                    *context_menu = None;
 3003                    None
 3004                }
 3005                None => None,
 3006            };
 3007            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3008            drop(context_menu);
 3009
 3010            if effects.completions {
 3011                if let Some(completion_position) = completion_position {
 3012                    let start_offset = selection_start.to_offset(buffer);
 3013                    let position_matches = start_offset == completion_position.to_offset(buffer);
 3014                    let continue_showing = if position_matches {
 3015                        if self.snippet_stack.is_empty() {
 3016                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3017                        } else {
 3018                            // Snippet choices can be shown even when the cursor is in whitespace.
 3019                            // Dismissing the menu with actions like backspace is handled by
 3020                            // invalidation regions.
 3021                            true
 3022                        }
 3023                    } else {
 3024                        false
 3025                    };
 3026
 3027                    if continue_showing {
 3028                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3029                    } else {
 3030                        self.hide_context_menu(window, cx);
 3031                    }
 3032                }
 3033            }
 3034
 3035            hide_hover(self, cx);
 3036
 3037            if old_cursor_position.to_display_point(&display_map).row()
 3038                != new_cursor_position.to_display_point(&display_map).row()
 3039            {
 3040                self.available_code_actions.take();
 3041            }
 3042            self.refresh_code_actions(window, cx);
 3043            self.refresh_document_highlights(cx);
 3044            self.refresh_selected_text_highlights(false, window, cx);
 3045            refresh_matching_bracket_highlights(self, window, cx);
 3046            self.update_visible_inline_completion(window, cx);
 3047            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3048            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3049            self.inline_blame_popover.take();
 3050            if self.git_blame_inline_enabled {
 3051                self.start_inline_blame_timer(window, cx);
 3052            }
 3053        }
 3054
 3055        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3056        cx.emit(EditorEvent::SelectionsChanged { local });
 3057
 3058        let selections = &self.selections.disjoint;
 3059        if selections.len() == 1 {
 3060            cx.emit(SearchEvent::ActiveMatchChanged)
 3061        }
 3062        if local {
 3063            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3064                let inmemory_selections = selections
 3065                    .iter()
 3066                    .map(|s| {
 3067                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3068                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3069                    })
 3070                    .collect();
 3071                self.update_restoration_data(cx, |data| {
 3072                    data.selections = inmemory_selections;
 3073                });
 3074
 3075                if WorkspaceSettings::get(None, cx).restore_on_startup
 3076                    != RestoreOnStartupBehavior::None
 3077                {
 3078                    if let Some(workspace_id) =
 3079                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 3080                    {
 3081                        let snapshot = self.buffer().read(cx).snapshot(cx);
 3082                        let selections = selections.clone();
 3083                        let background_executor = cx.background_executor().clone();
 3084                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3085                        self.serialize_selections = cx.background_spawn(async move {
 3086                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3087                            let db_selections = selections
 3088                                .iter()
 3089                                .map(|selection| {
 3090                                    (
 3091                                        selection.start.to_offset(&snapshot),
 3092                                        selection.end.to_offset(&snapshot),
 3093                                    )
 3094                                })
 3095                                .collect();
 3096
 3097                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3098                                .await
 3099                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3100                                .log_err();
 3101                        });
 3102                    }
 3103                }
 3104            }
 3105        }
 3106
 3107        cx.notify();
 3108    }
 3109
 3110    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3111        use text::ToOffset as _;
 3112        use text::ToPoint as _;
 3113
 3114        if self.mode.is_minimap()
 3115            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3116        {
 3117            return;
 3118        }
 3119
 3120        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3121            return;
 3122        };
 3123
 3124        let snapshot = singleton.read(cx).snapshot();
 3125        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3126            let display_snapshot = display_map.snapshot(cx);
 3127
 3128            display_snapshot
 3129                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3130                .map(|fold| {
 3131                    fold.range.start.text_anchor.to_point(&snapshot)
 3132                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3133                })
 3134                .collect()
 3135        });
 3136        self.update_restoration_data(cx, |data| {
 3137            data.folds = inmemory_folds;
 3138        });
 3139
 3140        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3141            return;
 3142        };
 3143        let background_executor = cx.background_executor().clone();
 3144        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3145        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3146            display_map
 3147                .snapshot(cx)
 3148                .folds_in_range(0..snapshot.len())
 3149                .map(|fold| {
 3150                    (
 3151                        fold.range.start.text_anchor.to_offset(&snapshot),
 3152                        fold.range.end.text_anchor.to_offset(&snapshot),
 3153                    )
 3154                })
 3155                .collect()
 3156        });
 3157        self.serialize_folds = cx.background_spawn(async move {
 3158            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3159            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3160                .await
 3161                .with_context(|| {
 3162                    format!(
 3163                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3164                    )
 3165                })
 3166                .log_err();
 3167        });
 3168    }
 3169
 3170    pub fn sync_selections(
 3171        &mut self,
 3172        other: Entity<Editor>,
 3173        cx: &mut Context<Self>,
 3174    ) -> gpui::Subscription {
 3175        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3176        self.selections.change_with(cx, |selections| {
 3177            selections.select_anchors(other_selections);
 3178        });
 3179
 3180        let other_subscription =
 3181            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3182                EditorEvent::SelectionsChanged { local: true } => {
 3183                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3184                    if other_selections.is_empty() {
 3185                        return;
 3186                    }
 3187                    this.selections.change_with(cx, |selections| {
 3188                        selections.select_anchors(other_selections);
 3189                    });
 3190                }
 3191                _ => {}
 3192            });
 3193
 3194        let this_subscription =
 3195            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3196                EditorEvent::SelectionsChanged { local: true } => {
 3197                    let these_selections = this.selections.disjoint.to_vec();
 3198                    if these_selections.is_empty() {
 3199                        return;
 3200                    }
 3201                    other.update(cx, |other_editor, cx| {
 3202                        other_editor.selections.change_with(cx, |selections| {
 3203                            selections.select_anchors(these_selections);
 3204                        })
 3205                    });
 3206                }
 3207                _ => {}
 3208            });
 3209
 3210        Subscription::join(other_subscription, this_subscription)
 3211    }
 3212
 3213    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3214    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3215    /// effects of selection change occur at the end of the transaction.
 3216    pub fn change_selections<R>(
 3217        &mut self,
 3218        effects: SelectionEffects,
 3219        window: &mut Window,
 3220        cx: &mut Context<Self>,
 3221        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3222    ) -> R {
 3223        if let Some(state) = &mut self.deferred_selection_effects_state {
 3224            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3225            state.effects.completions = effects.completions;
 3226            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3227            let (changed, result) = self.selections.change_with(cx, change);
 3228            state.changed |= changed;
 3229            return result;
 3230        }
 3231        let mut state = DeferredSelectionEffectsState {
 3232            changed: false,
 3233            effects,
 3234            old_cursor_position: self.selections.newest_anchor().head(),
 3235            history_entry: SelectionHistoryEntry {
 3236                selections: self.selections.disjoint_anchors(),
 3237                select_next_state: self.select_next_state.clone(),
 3238                select_prev_state: self.select_prev_state.clone(),
 3239                add_selections_state: self.add_selections_state.clone(),
 3240            },
 3241        };
 3242        let (changed, result) = self.selections.change_with(cx, change);
 3243        state.changed = state.changed || changed;
 3244        if self.defer_selection_effects {
 3245            self.deferred_selection_effects_state = Some(state);
 3246        } else {
 3247            self.apply_selection_effects(state, window, cx);
 3248        }
 3249        result
 3250    }
 3251
 3252    /// Defers the effects of selection change, so that the effects of multiple calls to
 3253    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3254    /// to selection history and the state of popovers based on selection position aren't
 3255    /// erroneously updated.
 3256    pub fn with_selection_effects_deferred<R>(
 3257        &mut self,
 3258        window: &mut Window,
 3259        cx: &mut Context<Self>,
 3260        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3261    ) -> R {
 3262        let already_deferred = self.defer_selection_effects;
 3263        self.defer_selection_effects = true;
 3264        let result = update(self, window, cx);
 3265        if !already_deferred {
 3266            self.defer_selection_effects = false;
 3267            if let Some(state) = self.deferred_selection_effects_state.take() {
 3268                self.apply_selection_effects(state, window, cx);
 3269            }
 3270        }
 3271        result
 3272    }
 3273
 3274    fn apply_selection_effects(
 3275        &mut self,
 3276        state: DeferredSelectionEffectsState,
 3277        window: &mut Window,
 3278        cx: &mut Context<Self>,
 3279    ) {
 3280        if state.changed {
 3281            self.selection_history.push(state.history_entry);
 3282
 3283            if let Some(autoscroll) = state.effects.scroll {
 3284                self.request_autoscroll(autoscroll, cx);
 3285            }
 3286
 3287            let old_cursor_position = &state.old_cursor_position;
 3288
 3289            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3290
 3291            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3292                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3293            }
 3294        }
 3295    }
 3296
 3297    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3298    where
 3299        I: IntoIterator<Item = (Range<S>, T)>,
 3300        S: ToOffset,
 3301        T: Into<Arc<str>>,
 3302    {
 3303        if self.read_only(cx) {
 3304            return;
 3305        }
 3306
 3307        self.buffer
 3308            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3309    }
 3310
 3311    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3312    where
 3313        I: IntoIterator<Item = (Range<S>, T)>,
 3314        S: ToOffset,
 3315        T: Into<Arc<str>>,
 3316    {
 3317        if self.read_only(cx) {
 3318            return;
 3319        }
 3320
 3321        self.buffer.update(cx, |buffer, cx| {
 3322            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3323        });
 3324    }
 3325
 3326    pub fn edit_with_block_indent<I, S, T>(
 3327        &mut self,
 3328        edits: I,
 3329        original_indent_columns: Vec<Option<u32>>,
 3330        cx: &mut Context<Self>,
 3331    ) where
 3332        I: IntoIterator<Item = (Range<S>, T)>,
 3333        S: ToOffset,
 3334        T: Into<Arc<str>>,
 3335    {
 3336        if self.read_only(cx) {
 3337            return;
 3338        }
 3339
 3340        self.buffer.update(cx, |buffer, cx| {
 3341            buffer.edit(
 3342                edits,
 3343                Some(AutoindentMode::Block {
 3344                    original_indent_columns,
 3345                }),
 3346                cx,
 3347            )
 3348        });
 3349    }
 3350
 3351    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3352        self.hide_context_menu(window, cx);
 3353
 3354        match phase {
 3355            SelectPhase::Begin {
 3356                position,
 3357                add,
 3358                click_count,
 3359            } => self.begin_selection(position, add, click_count, window, cx),
 3360            SelectPhase::BeginColumnar {
 3361                position,
 3362                goal_column,
 3363                reset,
 3364                mode,
 3365            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3366            SelectPhase::Extend {
 3367                position,
 3368                click_count,
 3369            } => self.extend_selection(position, click_count, window, cx),
 3370            SelectPhase::Update {
 3371                position,
 3372                goal_column,
 3373                scroll_delta,
 3374            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3375            SelectPhase::End => self.end_selection(window, cx),
 3376        }
 3377    }
 3378
 3379    fn extend_selection(
 3380        &mut self,
 3381        position: DisplayPoint,
 3382        click_count: usize,
 3383        window: &mut Window,
 3384        cx: &mut Context<Self>,
 3385    ) {
 3386        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3387        let tail = self.selections.newest::<usize>(cx).tail();
 3388        self.begin_selection(position, false, click_count, window, cx);
 3389
 3390        let position = position.to_offset(&display_map, Bias::Left);
 3391        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3392
 3393        let mut pending_selection = self
 3394            .selections
 3395            .pending_anchor()
 3396            .expect("extend_selection not called with pending selection");
 3397        if position >= tail {
 3398            pending_selection.start = tail_anchor;
 3399        } else {
 3400            pending_selection.end = tail_anchor;
 3401            pending_selection.reversed = true;
 3402        }
 3403
 3404        let mut pending_mode = self.selections.pending_mode().unwrap();
 3405        match &mut pending_mode {
 3406            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3407            _ => {}
 3408        }
 3409
 3410        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3411            SelectionEffects::scroll(Autoscroll::fit())
 3412        } else {
 3413            SelectionEffects::no_scroll()
 3414        };
 3415
 3416        self.change_selections(effects, window, cx, |s| {
 3417            s.set_pending(pending_selection, pending_mode)
 3418        });
 3419    }
 3420
 3421    fn begin_selection(
 3422        &mut self,
 3423        position: DisplayPoint,
 3424        add: bool,
 3425        click_count: usize,
 3426        window: &mut Window,
 3427        cx: &mut Context<Self>,
 3428    ) {
 3429        if !self.focus_handle.is_focused(window) {
 3430            self.last_focused_descendant = None;
 3431            window.focus(&self.focus_handle);
 3432        }
 3433
 3434        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3435        let buffer = &display_map.buffer_snapshot;
 3436        let position = display_map.clip_point(position, Bias::Left);
 3437
 3438        let start;
 3439        let end;
 3440        let mode;
 3441        let mut auto_scroll;
 3442        match click_count {
 3443            1 => {
 3444                start = buffer.anchor_before(position.to_point(&display_map));
 3445                end = start;
 3446                mode = SelectMode::Character;
 3447                auto_scroll = true;
 3448            }
 3449            2 => {
 3450                let position = display_map
 3451                    .clip_point(position, Bias::Left)
 3452                    .to_offset(&display_map, Bias::Left);
 3453                let (range, _) = buffer.surrounding_word(position, false);
 3454                start = buffer.anchor_before(range.start);
 3455                end = buffer.anchor_before(range.end);
 3456                mode = SelectMode::Word(start..end);
 3457                auto_scroll = true;
 3458            }
 3459            3 => {
 3460                let position = display_map
 3461                    .clip_point(position, Bias::Left)
 3462                    .to_point(&display_map);
 3463                let line_start = display_map.prev_line_boundary(position).0;
 3464                let next_line_start = buffer.clip_point(
 3465                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3466                    Bias::Left,
 3467                );
 3468                start = buffer.anchor_before(line_start);
 3469                end = buffer.anchor_before(next_line_start);
 3470                mode = SelectMode::Line(start..end);
 3471                auto_scroll = true;
 3472            }
 3473            _ => {
 3474                start = buffer.anchor_before(0);
 3475                end = buffer.anchor_before(buffer.len());
 3476                mode = SelectMode::All;
 3477                auto_scroll = false;
 3478            }
 3479        }
 3480        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3481
 3482        let point_to_delete: Option<usize> = {
 3483            let selected_points: Vec<Selection<Point>> =
 3484                self.selections.disjoint_in_range(start..end, cx);
 3485
 3486            if !add || click_count > 1 {
 3487                None
 3488            } else if !selected_points.is_empty() {
 3489                Some(selected_points[0].id)
 3490            } else {
 3491                let clicked_point_already_selected =
 3492                    self.selections.disjoint.iter().find(|selection| {
 3493                        selection.start.to_point(buffer) == start.to_point(buffer)
 3494                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3495                    });
 3496
 3497                clicked_point_already_selected.map(|selection| selection.id)
 3498            }
 3499        };
 3500
 3501        let selections_count = self.selections.count();
 3502        let effects = if auto_scroll {
 3503            SelectionEffects::default()
 3504        } else {
 3505            SelectionEffects::no_scroll()
 3506        };
 3507
 3508        self.change_selections(effects, window, cx, |s| {
 3509            if let Some(point_to_delete) = point_to_delete {
 3510                s.delete(point_to_delete);
 3511
 3512                if selections_count == 1 {
 3513                    s.set_pending_anchor_range(start..end, mode);
 3514                }
 3515            } else {
 3516                if !add {
 3517                    s.clear_disjoint();
 3518                }
 3519
 3520                s.set_pending_anchor_range(start..end, mode);
 3521            }
 3522        });
 3523    }
 3524
 3525    fn begin_columnar_selection(
 3526        &mut self,
 3527        position: DisplayPoint,
 3528        goal_column: u32,
 3529        reset: bool,
 3530        mode: ColumnarMode,
 3531        window: &mut Window,
 3532        cx: &mut Context<Self>,
 3533    ) {
 3534        if !self.focus_handle.is_focused(window) {
 3535            self.last_focused_descendant = None;
 3536            window.focus(&self.focus_handle);
 3537        }
 3538
 3539        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3540
 3541        if reset {
 3542            let pointer_position = display_map
 3543                .buffer_snapshot
 3544                .anchor_before(position.to_point(&display_map));
 3545
 3546            self.change_selections(
 3547                SelectionEffects::scroll(Autoscroll::newest()),
 3548                window,
 3549                cx,
 3550                |s| {
 3551                    s.clear_disjoint();
 3552                    s.set_pending_anchor_range(
 3553                        pointer_position..pointer_position,
 3554                        SelectMode::Character,
 3555                    );
 3556                },
 3557            );
 3558        };
 3559
 3560        let tail = self.selections.newest::<Point>(cx).tail();
 3561        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3562        self.columnar_selection_state = match mode {
 3563            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3564                selection_tail: selection_anchor,
 3565                display_point: if reset {
 3566                    if position.column() != goal_column {
 3567                        Some(DisplayPoint::new(position.row(), goal_column))
 3568                    } else {
 3569                        None
 3570                    }
 3571                } else {
 3572                    None
 3573                },
 3574            }),
 3575            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3576                selection_tail: selection_anchor,
 3577            }),
 3578        };
 3579
 3580        if !reset {
 3581            self.select_columns(position, goal_column, &display_map, window, cx);
 3582        }
 3583    }
 3584
 3585    fn update_selection(
 3586        &mut self,
 3587        position: DisplayPoint,
 3588        goal_column: u32,
 3589        scroll_delta: gpui::Point<f32>,
 3590        window: &mut Window,
 3591        cx: &mut Context<Self>,
 3592    ) {
 3593        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3594
 3595        if self.columnar_selection_state.is_some() {
 3596            self.select_columns(position, goal_column, &display_map, window, cx);
 3597        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3598            let buffer = &display_map.buffer_snapshot;
 3599            let head;
 3600            let tail;
 3601            let mode = self.selections.pending_mode().unwrap();
 3602            match &mode {
 3603                SelectMode::Character => {
 3604                    head = position.to_point(&display_map);
 3605                    tail = pending.tail().to_point(buffer);
 3606                }
 3607                SelectMode::Word(original_range) => {
 3608                    let offset = display_map
 3609                        .clip_point(position, Bias::Left)
 3610                        .to_offset(&display_map, Bias::Left);
 3611                    let original_range = original_range.to_offset(buffer);
 3612
 3613                    let head_offset = if buffer.is_inside_word(offset, false)
 3614                        || original_range.contains(&offset)
 3615                    {
 3616                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3617                        if word_range.start < original_range.start {
 3618                            word_range.start
 3619                        } else {
 3620                            word_range.end
 3621                        }
 3622                    } else {
 3623                        offset
 3624                    };
 3625
 3626                    head = head_offset.to_point(buffer);
 3627                    if head_offset <= original_range.start {
 3628                        tail = original_range.end.to_point(buffer);
 3629                    } else {
 3630                        tail = original_range.start.to_point(buffer);
 3631                    }
 3632                }
 3633                SelectMode::Line(original_range) => {
 3634                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3635
 3636                    let position = display_map
 3637                        .clip_point(position, Bias::Left)
 3638                        .to_point(&display_map);
 3639                    let line_start = display_map.prev_line_boundary(position).0;
 3640                    let next_line_start = buffer.clip_point(
 3641                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3642                        Bias::Left,
 3643                    );
 3644
 3645                    if line_start < original_range.start {
 3646                        head = line_start
 3647                    } else {
 3648                        head = next_line_start
 3649                    }
 3650
 3651                    if head <= original_range.start {
 3652                        tail = original_range.end;
 3653                    } else {
 3654                        tail = original_range.start;
 3655                    }
 3656                }
 3657                SelectMode::All => {
 3658                    return;
 3659                }
 3660            };
 3661
 3662            if head < tail {
 3663                pending.start = buffer.anchor_before(head);
 3664                pending.end = buffer.anchor_before(tail);
 3665                pending.reversed = true;
 3666            } else {
 3667                pending.start = buffer.anchor_before(tail);
 3668                pending.end = buffer.anchor_before(head);
 3669                pending.reversed = false;
 3670            }
 3671
 3672            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3673                s.set_pending(pending, mode);
 3674            });
 3675        } else {
 3676            log::error!("update_selection dispatched with no pending selection");
 3677            return;
 3678        }
 3679
 3680        self.apply_scroll_delta(scroll_delta, window, cx);
 3681        cx.notify();
 3682    }
 3683
 3684    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3685        self.columnar_selection_state.take();
 3686        if self.selections.pending_anchor().is_some() {
 3687            let selections = self.selections.all::<usize>(cx);
 3688            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3689                s.select(selections);
 3690                s.clear_pending();
 3691            });
 3692        }
 3693    }
 3694
 3695    fn select_columns(
 3696        &mut self,
 3697        head: DisplayPoint,
 3698        goal_column: u32,
 3699        display_map: &DisplaySnapshot,
 3700        window: &mut Window,
 3701        cx: &mut Context<Self>,
 3702    ) {
 3703        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3704            return;
 3705        };
 3706
 3707        let tail = match columnar_state {
 3708            ColumnarSelectionState::FromMouse {
 3709                selection_tail,
 3710                display_point,
 3711            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(&display_map)),
 3712            ColumnarSelectionState::FromSelection { selection_tail } => {
 3713                selection_tail.to_display_point(&display_map)
 3714            }
 3715        };
 3716
 3717        let start_row = cmp::min(tail.row(), head.row());
 3718        let end_row = cmp::max(tail.row(), head.row());
 3719        let start_column = cmp::min(tail.column(), goal_column);
 3720        let end_column = cmp::max(tail.column(), goal_column);
 3721        let reversed = start_column < tail.column();
 3722
 3723        let selection_ranges = (start_row.0..=end_row.0)
 3724            .map(DisplayRow)
 3725            .filter_map(|row| {
 3726                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3727                    || start_column <= display_map.line_len(row))
 3728                    && !display_map.is_block_line(row)
 3729                {
 3730                    let start = display_map
 3731                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3732                        .to_point(display_map);
 3733                    let end = display_map
 3734                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3735                        .to_point(display_map);
 3736                    if reversed {
 3737                        Some(end..start)
 3738                    } else {
 3739                        Some(start..end)
 3740                    }
 3741                } else {
 3742                    None
 3743                }
 3744            })
 3745            .collect::<Vec<_>>();
 3746
 3747        let ranges = match columnar_state {
 3748            ColumnarSelectionState::FromMouse { .. } => {
 3749                let mut non_empty_ranges = selection_ranges
 3750                    .iter()
 3751                    .filter(|selection_range| selection_range.start != selection_range.end)
 3752                    .peekable();
 3753                if non_empty_ranges.peek().is_some() {
 3754                    non_empty_ranges.cloned().collect()
 3755                } else {
 3756                    selection_ranges
 3757                }
 3758            }
 3759            _ => selection_ranges,
 3760        };
 3761
 3762        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3763            s.select_ranges(ranges);
 3764        });
 3765        cx.notify();
 3766    }
 3767
 3768    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3769        self.selections
 3770            .all_adjusted(cx)
 3771            .iter()
 3772            .any(|selection| !selection.is_empty())
 3773    }
 3774
 3775    pub fn has_pending_nonempty_selection(&self) -> bool {
 3776        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3777            Some(Selection { start, end, .. }) => start != end,
 3778            None => false,
 3779        };
 3780
 3781        pending_nonempty_selection
 3782            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3783    }
 3784
 3785    pub fn has_pending_selection(&self) -> bool {
 3786        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3787    }
 3788
 3789    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3790        self.selection_mark_mode = false;
 3791        self.selection_drag_state = SelectionDragState::None;
 3792
 3793        if self.clear_expanded_diff_hunks(cx) {
 3794            cx.notify();
 3795            return;
 3796        }
 3797        if self.dismiss_menus_and_popups(true, window, cx) {
 3798            return;
 3799        }
 3800
 3801        if self.mode.is_full()
 3802            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3803        {
 3804            return;
 3805        }
 3806
 3807        cx.propagate();
 3808    }
 3809
 3810    pub fn dismiss_menus_and_popups(
 3811        &mut self,
 3812        is_user_requested: bool,
 3813        window: &mut Window,
 3814        cx: &mut Context<Self>,
 3815    ) -> bool {
 3816        if self.take_rename(false, window, cx).is_some() {
 3817            return true;
 3818        }
 3819
 3820        if hide_hover(self, cx) {
 3821            return true;
 3822        }
 3823
 3824        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3825            return true;
 3826        }
 3827
 3828        if self.hide_context_menu(window, cx).is_some() {
 3829            return true;
 3830        }
 3831
 3832        if self.mouse_context_menu.take().is_some() {
 3833            return true;
 3834        }
 3835
 3836        if is_user_requested && self.discard_inline_completion(true, cx) {
 3837            return true;
 3838        }
 3839
 3840        if self.snippet_stack.pop().is_some() {
 3841            return true;
 3842        }
 3843
 3844        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3845            self.dismiss_diagnostics(cx);
 3846            return true;
 3847        }
 3848
 3849        false
 3850    }
 3851
 3852    fn linked_editing_ranges_for(
 3853        &self,
 3854        selection: Range<text::Anchor>,
 3855        cx: &App,
 3856    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3857        if self.linked_edit_ranges.is_empty() {
 3858            return None;
 3859        }
 3860        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3861            selection.end.buffer_id.and_then(|end_buffer_id| {
 3862                if selection.start.buffer_id != Some(end_buffer_id) {
 3863                    return None;
 3864                }
 3865                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3866                let snapshot = buffer.read(cx).snapshot();
 3867                self.linked_edit_ranges
 3868                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3869                    .map(|ranges| (ranges, snapshot, buffer))
 3870            })?;
 3871        use text::ToOffset as TO;
 3872        // find offset from the start of current range to current cursor position
 3873        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3874
 3875        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3876        let start_difference = start_offset - start_byte_offset;
 3877        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3878        let end_difference = end_offset - start_byte_offset;
 3879        // Current range has associated linked ranges.
 3880        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3881        for range in linked_ranges.iter() {
 3882            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3883            let end_offset = start_offset + end_difference;
 3884            let start_offset = start_offset + start_difference;
 3885            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3886                continue;
 3887            }
 3888            if self.selections.disjoint_anchor_ranges().any(|s| {
 3889                if s.start.buffer_id != selection.start.buffer_id
 3890                    || s.end.buffer_id != selection.end.buffer_id
 3891                {
 3892                    return false;
 3893                }
 3894                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3895                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3896            }) {
 3897                continue;
 3898            }
 3899            let start = buffer_snapshot.anchor_after(start_offset);
 3900            let end = buffer_snapshot.anchor_after(end_offset);
 3901            linked_edits
 3902                .entry(buffer.clone())
 3903                .or_default()
 3904                .push(start..end);
 3905        }
 3906        Some(linked_edits)
 3907    }
 3908
 3909    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3910        let text: Arc<str> = text.into();
 3911
 3912        if self.read_only(cx) {
 3913            return;
 3914        }
 3915
 3916        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3917
 3918        let selections = self.selections.all_adjusted(cx);
 3919        let mut bracket_inserted = false;
 3920        let mut edits = Vec::new();
 3921        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3922        let mut new_selections = Vec::with_capacity(selections.len());
 3923        let mut new_autoclose_regions = Vec::new();
 3924        let snapshot = self.buffer.read(cx).read(cx);
 3925        let mut clear_linked_edit_ranges = false;
 3926
 3927        for (selection, autoclose_region) in
 3928            self.selections_with_autoclose_regions(selections, &snapshot)
 3929        {
 3930            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3931                // Determine if the inserted text matches the opening or closing
 3932                // bracket of any of this language's bracket pairs.
 3933                let mut bracket_pair = None;
 3934                let mut is_bracket_pair_start = false;
 3935                let mut is_bracket_pair_end = false;
 3936                if !text.is_empty() {
 3937                    let mut bracket_pair_matching_end = None;
 3938                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3939                    //  and they are removing the character that triggered IME popup.
 3940                    for (pair, enabled) in scope.brackets() {
 3941                        if !pair.close && !pair.surround {
 3942                            continue;
 3943                        }
 3944
 3945                        if enabled && pair.start.ends_with(text.as_ref()) {
 3946                            let prefix_len = pair.start.len() - text.len();
 3947                            let preceding_text_matches_prefix = prefix_len == 0
 3948                                || (selection.start.column >= (prefix_len as u32)
 3949                                    && snapshot.contains_str_at(
 3950                                        Point::new(
 3951                                            selection.start.row,
 3952                                            selection.start.column - (prefix_len as u32),
 3953                                        ),
 3954                                        &pair.start[..prefix_len],
 3955                                    ));
 3956                            if preceding_text_matches_prefix {
 3957                                bracket_pair = Some(pair.clone());
 3958                                is_bracket_pair_start = true;
 3959                                break;
 3960                            }
 3961                        }
 3962                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3963                        {
 3964                            // take first bracket pair matching end, but don't break in case a later bracket
 3965                            // pair matches start
 3966                            bracket_pair_matching_end = Some(pair.clone());
 3967                        }
 3968                    }
 3969                    if let Some(end) = bracket_pair_matching_end
 3970                        && bracket_pair.is_none()
 3971                    {
 3972                        bracket_pair = Some(end);
 3973                        is_bracket_pair_end = true;
 3974                    }
 3975                }
 3976
 3977                if let Some(bracket_pair) = bracket_pair {
 3978                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3979                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3980                    let auto_surround =
 3981                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3982                    if selection.is_empty() {
 3983                        if is_bracket_pair_start {
 3984                            // If the inserted text is a suffix of an opening bracket and the
 3985                            // selection is preceded by the rest of the opening bracket, then
 3986                            // insert the closing bracket.
 3987                            let following_text_allows_autoclose = snapshot
 3988                                .chars_at(selection.start)
 3989                                .next()
 3990                                .map_or(true, |c| scope.should_autoclose_before(c));
 3991
 3992                            let preceding_text_allows_autoclose = selection.start.column == 0
 3993                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3994                                    true,
 3995                                    |c| {
 3996                                        bracket_pair.start != bracket_pair.end
 3997                                            || !snapshot
 3998                                                .char_classifier_at(selection.start)
 3999                                                .is_word(c)
 4000                                    },
 4001                                );
 4002
 4003                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4004                                && bracket_pair.start.len() == 1
 4005                            {
 4006                                let target = bracket_pair.start.chars().next().unwrap();
 4007                                let current_line_count = snapshot
 4008                                    .reversed_chars_at(selection.start)
 4009                                    .take_while(|&c| c != '\n')
 4010                                    .filter(|&c| c == target)
 4011                                    .count();
 4012                                current_line_count % 2 == 1
 4013                            } else {
 4014                                false
 4015                            };
 4016
 4017                            if autoclose
 4018                                && bracket_pair.close
 4019                                && following_text_allows_autoclose
 4020                                && preceding_text_allows_autoclose
 4021                                && !is_closing_quote
 4022                            {
 4023                                let anchor = snapshot.anchor_before(selection.end);
 4024                                new_selections.push((selection.map(|_| anchor), text.len()));
 4025                                new_autoclose_regions.push((
 4026                                    anchor,
 4027                                    text.len(),
 4028                                    selection.id,
 4029                                    bracket_pair.clone(),
 4030                                ));
 4031                                edits.push((
 4032                                    selection.range(),
 4033                                    format!("{}{}", text, bracket_pair.end).into(),
 4034                                ));
 4035                                bracket_inserted = true;
 4036                                continue;
 4037                            }
 4038                        }
 4039
 4040                        if let Some(region) = autoclose_region {
 4041                            // If the selection is followed by an auto-inserted closing bracket,
 4042                            // then don't insert that closing bracket again; just move the selection
 4043                            // past the closing bracket.
 4044                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4045                                && text.as_ref() == region.pair.end.as_str()
 4046                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4047                            if should_skip {
 4048                                let anchor = snapshot.anchor_after(selection.end);
 4049                                new_selections
 4050                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4051                                continue;
 4052                            }
 4053                        }
 4054
 4055                        let always_treat_brackets_as_autoclosed = snapshot
 4056                            .language_settings_at(selection.start, cx)
 4057                            .always_treat_brackets_as_autoclosed;
 4058                        if always_treat_brackets_as_autoclosed
 4059                            && is_bracket_pair_end
 4060                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4061                        {
 4062                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4063                            // and the inserted text is a closing bracket and the selection is followed
 4064                            // by the closing bracket then move the selection past the closing bracket.
 4065                            let anchor = snapshot.anchor_after(selection.end);
 4066                            new_selections.push((selection.map(|_| anchor), text.len()));
 4067                            continue;
 4068                        }
 4069                    }
 4070                    // If an opening bracket is 1 character long and is typed while
 4071                    // text is selected, then surround that text with the bracket pair.
 4072                    else if auto_surround
 4073                        && bracket_pair.surround
 4074                        && is_bracket_pair_start
 4075                        && bracket_pair.start.chars().count() == 1
 4076                    {
 4077                        edits.push((selection.start..selection.start, text.clone()));
 4078                        edits.push((
 4079                            selection.end..selection.end,
 4080                            bracket_pair.end.as_str().into(),
 4081                        ));
 4082                        bracket_inserted = true;
 4083                        new_selections.push((
 4084                            Selection {
 4085                                id: selection.id,
 4086                                start: snapshot.anchor_after(selection.start),
 4087                                end: snapshot.anchor_before(selection.end),
 4088                                reversed: selection.reversed,
 4089                                goal: selection.goal,
 4090                            },
 4091                            0,
 4092                        ));
 4093                        continue;
 4094                    }
 4095                }
 4096            }
 4097
 4098            if self.auto_replace_emoji_shortcode
 4099                && selection.is_empty()
 4100                && text.as_ref().ends_with(':')
 4101            {
 4102                if let Some(possible_emoji_short_code) =
 4103                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4104                {
 4105                    if !possible_emoji_short_code.is_empty() {
 4106                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 4107                            let emoji_shortcode_start = Point::new(
 4108                                selection.start.row,
 4109                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4110                            );
 4111
 4112                            // Remove shortcode from buffer
 4113                            edits.push((
 4114                                emoji_shortcode_start..selection.start,
 4115                                "".to_string().into(),
 4116                            ));
 4117                            new_selections.push((
 4118                                Selection {
 4119                                    id: selection.id,
 4120                                    start: snapshot.anchor_after(emoji_shortcode_start),
 4121                                    end: snapshot.anchor_before(selection.start),
 4122                                    reversed: selection.reversed,
 4123                                    goal: selection.goal,
 4124                                },
 4125                                0,
 4126                            ));
 4127
 4128                            // Insert emoji
 4129                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 4130                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4131                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 4132
 4133                            continue;
 4134                        }
 4135                    }
 4136                }
 4137            }
 4138
 4139            // If not handling any auto-close operation, then just replace the selected
 4140            // text with the given input and move the selection to the end of the
 4141            // newly inserted text.
 4142            let anchor = snapshot.anchor_after(selection.end);
 4143            if !self.linked_edit_ranges.is_empty() {
 4144                let start_anchor = snapshot.anchor_before(selection.start);
 4145
 4146                let is_word_char = text.chars().next().map_or(true, |char| {
 4147                    let classifier = snapshot
 4148                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4149                        .ignore_punctuation(true);
 4150                    classifier.is_word(char)
 4151                });
 4152
 4153                if is_word_char {
 4154                    if let Some(ranges) = self
 4155                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4156                    {
 4157                        for (buffer, edits) in ranges {
 4158                            linked_edits
 4159                                .entry(buffer.clone())
 4160                                .or_default()
 4161                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4162                        }
 4163                    }
 4164                } else {
 4165                    clear_linked_edit_ranges = true;
 4166                }
 4167            }
 4168
 4169            new_selections.push((selection.map(|_| anchor), 0));
 4170            edits.push((selection.start..selection.end, text.clone()));
 4171        }
 4172
 4173        drop(snapshot);
 4174
 4175        self.transact(window, cx, |this, window, cx| {
 4176            if clear_linked_edit_ranges {
 4177                this.linked_edit_ranges.clear();
 4178            }
 4179            let initial_buffer_versions =
 4180                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4181
 4182            this.buffer.update(cx, |buffer, cx| {
 4183                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4184            });
 4185            for (buffer, edits) in linked_edits {
 4186                buffer.update(cx, |buffer, cx| {
 4187                    let snapshot = buffer.snapshot();
 4188                    let edits = edits
 4189                        .into_iter()
 4190                        .map(|(range, text)| {
 4191                            use text::ToPoint as TP;
 4192                            let end_point = TP::to_point(&range.end, &snapshot);
 4193                            let start_point = TP::to_point(&range.start, &snapshot);
 4194                            (start_point..end_point, text)
 4195                        })
 4196                        .sorted_by_key(|(range, _)| range.start);
 4197                    buffer.edit(edits, None, cx);
 4198                })
 4199            }
 4200            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4201            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4202            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4203            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4204                .zip(new_selection_deltas)
 4205                .map(|(selection, delta)| Selection {
 4206                    id: selection.id,
 4207                    start: selection.start + delta,
 4208                    end: selection.end + delta,
 4209                    reversed: selection.reversed,
 4210                    goal: SelectionGoal::None,
 4211                })
 4212                .collect::<Vec<_>>();
 4213
 4214            let mut i = 0;
 4215            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4216                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4217                let start = map.buffer_snapshot.anchor_before(position);
 4218                let end = map.buffer_snapshot.anchor_after(position);
 4219                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4220                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4221                        Ordering::Less => i += 1,
 4222                        Ordering::Greater => break,
 4223                        Ordering::Equal => {
 4224                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4225                                Ordering::Less => i += 1,
 4226                                Ordering::Equal => break,
 4227                                Ordering::Greater => break,
 4228                            }
 4229                        }
 4230                    }
 4231                }
 4232                this.autoclose_regions.insert(
 4233                    i,
 4234                    AutocloseRegion {
 4235                        selection_id,
 4236                        range: start..end,
 4237                        pair,
 4238                    },
 4239                );
 4240            }
 4241
 4242            let had_active_inline_completion = this.has_active_inline_completion();
 4243            this.change_selections(
 4244                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4245                window,
 4246                cx,
 4247                |s| s.select(new_selections),
 4248            );
 4249
 4250            if !bracket_inserted {
 4251                if let Some(on_type_format_task) =
 4252                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4253                {
 4254                    on_type_format_task.detach_and_log_err(cx);
 4255                }
 4256            }
 4257
 4258            let editor_settings = EditorSettings::get_global(cx);
 4259            if bracket_inserted
 4260                && (editor_settings.auto_signature_help
 4261                    || editor_settings.show_signature_help_after_edits)
 4262            {
 4263                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4264            }
 4265
 4266            let trigger_in_words =
 4267                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4268            if this.hard_wrap.is_some() {
 4269                let latest: Range<Point> = this.selections.newest(cx).range();
 4270                if latest.is_empty()
 4271                    && this
 4272                        .buffer()
 4273                        .read(cx)
 4274                        .snapshot(cx)
 4275                        .line_len(MultiBufferRow(latest.start.row))
 4276                        == latest.start.column
 4277                {
 4278                    this.rewrap_impl(
 4279                        RewrapOptions {
 4280                            override_language_settings: true,
 4281                            preserve_existing_whitespace: true,
 4282                        },
 4283                        cx,
 4284                    )
 4285                }
 4286            }
 4287            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4288            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4289            this.refresh_inline_completion(true, false, window, cx);
 4290            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4291        });
 4292    }
 4293
 4294    fn find_possible_emoji_shortcode_at_position(
 4295        snapshot: &MultiBufferSnapshot,
 4296        position: Point,
 4297    ) -> Option<String> {
 4298        let mut chars = Vec::new();
 4299        let mut found_colon = false;
 4300        for char in snapshot.reversed_chars_at(position).take(100) {
 4301            // Found a possible emoji shortcode in the middle of the buffer
 4302            if found_colon {
 4303                if char.is_whitespace() {
 4304                    chars.reverse();
 4305                    return Some(chars.iter().collect());
 4306                }
 4307                // If the previous character is not a whitespace, we are in the middle of a word
 4308                // and we only want to complete the shortcode if the word is made up of other emojis
 4309                let mut containing_word = String::new();
 4310                for ch in snapshot
 4311                    .reversed_chars_at(position)
 4312                    .skip(chars.len() + 1)
 4313                    .take(100)
 4314                {
 4315                    if ch.is_whitespace() {
 4316                        break;
 4317                    }
 4318                    containing_word.push(ch);
 4319                }
 4320                let containing_word = containing_word.chars().rev().collect::<String>();
 4321                if util::word_consists_of_emojis(containing_word.as_str()) {
 4322                    chars.reverse();
 4323                    return Some(chars.iter().collect());
 4324                }
 4325            }
 4326
 4327            if char.is_whitespace() || !char.is_ascii() {
 4328                return None;
 4329            }
 4330            if char == ':' {
 4331                found_colon = true;
 4332            } else {
 4333                chars.push(char);
 4334            }
 4335        }
 4336        // Found a possible emoji shortcode at the beginning of the buffer
 4337        chars.reverse();
 4338        Some(chars.iter().collect())
 4339    }
 4340
 4341    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4342        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4343        self.transact(window, cx, |this, window, cx| {
 4344            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4345                let selections = this.selections.all::<usize>(cx);
 4346                let multi_buffer = this.buffer.read(cx);
 4347                let buffer = multi_buffer.snapshot(cx);
 4348                selections
 4349                    .iter()
 4350                    .map(|selection| {
 4351                        let start_point = selection.start.to_point(&buffer);
 4352                        let mut existing_indent =
 4353                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4354                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4355                        let start = selection.start;
 4356                        let end = selection.end;
 4357                        let selection_is_empty = start == end;
 4358                        let language_scope = buffer.language_scope_at(start);
 4359                        let (
 4360                            comment_delimiter,
 4361                            doc_delimiter,
 4362                            insert_extra_newline,
 4363                            indent_on_newline,
 4364                            indent_on_extra_newline,
 4365                        ) = if let Some(language) = &language_scope {
 4366                            let mut insert_extra_newline =
 4367                                insert_extra_newline_brackets(&buffer, start..end, language)
 4368                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4369
 4370                            // Comment extension on newline is allowed only for cursor selections
 4371                            let comment_delimiter = maybe!({
 4372                                if !selection_is_empty {
 4373                                    return None;
 4374                                }
 4375
 4376                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4377                                    return None;
 4378                                }
 4379
 4380                                let delimiters = language.line_comment_prefixes();
 4381                                let max_len_of_delimiter =
 4382                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4383                                let (snapshot, range) =
 4384                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4385
 4386                                let num_of_whitespaces = snapshot
 4387                                    .chars_for_range(range.clone())
 4388                                    .take_while(|c| c.is_whitespace())
 4389                                    .count();
 4390                                let comment_candidate = snapshot
 4391                                    .chars_for_range(range.clone())
 4392                                    .skip(num_of_whitespaces)
 4393                                    .take(max_len_of_delimiter)
 4394                                    .collect::<String>();
 4395                                let (delimiter, trimmed_len) = delimiters
 4396                                    .iter()
 4397                                    .filter_map(|delimiter| {
 4398                                        let prefix = delimiter.trim_end();
 4399                                        if comment_candidate.starts_with(prefix) {
 4400                                            Some((delimiter, prefix.len()))
 4401                                        } else {
 4402                                            None
 4403                                        }
 4404                                    })
 4405                                    .max_by_key(|(_, len)| *len)?;
 4406
 4407                                if let Some(BlockCommentConfig {
 4408                                    start: block_start, ..
 4409                                }) = language.block_comment()
 4410                                {
 4411                                    let block_start_trimmed = block_start.trim_end();
 4412                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4413                                        let line_content = snapshot
 4414                                            .chars_for_range(range)
 4415                                            .skip(num_of_whitespaces)
 4416                                            .take(block_start_trimmed.len())
 4417                                            .collect::<String>();
 4418
 4419                                        if line_content.starts_with(block_start_trimmed) {
 4420                                            return None;
 4421                                        }
 4422                                    }
 4423                                }
 4424
 4425                                let cursor_is_placed_after_comment_marker =
 4426                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4427                                if cursor_is_placed_after_comment_marker {
 4428                                    Some(delimiter.clone())
 4429                                } else {
 4430                                    None
 4431                                }
 4432                            });
 4433
 4434                            let mut indent_on_newline = IndentSize::spaces(0);
 4435                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4436
 4437                            let doc_delimiter = maybe!({
 4438                                if !selection_is_empty {
 4439                                    return None;
 4440                                }
 4441
 4442                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4443                                    return None;
 4444                                }
 4445
 4446                                let BlockCommentConfig {
 4447                                    start: start_tag,
 4448                                    end: end_tag,
 4449                                    prefix: delimiter,
 4450                                    tab_size: len,
 4451                                } = language.documentation_comment()?;
 4452                                let is_within_block_comment = buffer
 4453                                    .language_scope_at(start_point)
 4454                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4455                                if !is_within_block_comment {
 4456                                    return None;
 4457                                }
 4458
 4459                                let (snapshot, range) =
 4460                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4461
 4462                                let num_of_whitespaces = snapshot
 4463                                    .chars_for_range(range.clone())
 4464                                    .take_while(|c| c.is_whitespace())
 4465                                    .count();
 4466
 4467                                // It is safe to use a column from MultiBufferPoint in context of a single buffer ranges, because we're only ever looking at a single line at a time.
 4468                                let column = start_point.column;
 4469                                let cursor_is_after_start_tag = {
 4470                                    let start_tag_len = start_tag.len();
 4471                                    let start_tag_line = snapshot
 4472                                        .chars_for_range(range.clone())
 4473                                        .skip(num_of_whitespaces)
 4474                                        .take(start_tag_len)
 4475                                        .collect::<String>();
 4476                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4477                                        num_of_whitespaces + start_tag_len <= column as usize
 4478                                    } else {
 4479                                        false
 4480                                    }
 4481                                };
 4482
 4483                                let cursor_is_after_delimiter = {
 4484                                    let delimiter_trim = delimiter.trim_end();
 4485                                    let delimiter_line = snapshot
 4486                                        .chars_for_range(range.clone())
 4487                                        .skip(num_of_whitespaces)
 4488                                        .take(delimiter_trim.len())
 4489                                        .collect::<String>();
 4490                                    if delimiter_line.starts_with(delimiter_trim) {
 4491                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4492                                    } else {
 4493                                        false
 4494                                    }
 4495                                };
 4496
 4497                                let cursor_is_before_end_tag_if_exists = {
 4498                                    let mut char_position = 0u32;
 4499                                    let mut end_tag_offset = None;
 4500
 4501                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4502                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4503                                            let chars_before_match =
 4504                                                chunk[..byte_pos].chars().count() as u32;
 4505                                            end_tag_offset =
 4506                                                Some(char_position + chars_before_match);
 4507                                            break 'outer;
 4508                                        }
 4509                                        char_position += chunk.chars().count() as u32;
 4510                                    }
 4511
 4512                                    if let Some(end_tag_offset) = end_tag_offset {
 4513                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4514                                        if cursor_is_after_start_tag {
 4515                                            if cursor_is_before_end_tag {
 4516                                                insert_extra_newline = true;
 4517                                            }
 4518                                            let cursor_is_at_start_of_end_tag =
 4519                                                column == end_tag_offset;
 4520                                            if cursor_is_at_start_of_end_tag {
 4521                                                indent_on_extra_newline.len = *len;
 4522                                            }
 4523                                        }
 4524                                        cursor_is_before_end_tag
 4525                                    } else {
 4526                                        true
 4527                                    }
 4528                                };
 4529
 4530                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4531                                    && cursor_is_before_end_tag_if_exists
 4532                                {
 4533                                    if cursor_is_after_start_tag {
 4534                                        indent_on_newline.len = *len;
 4535                                    }
 4536                                    Some(delimiter.clone())
 4537                                } else {
 4538                                    None
 4539                                }
 4540                            });
 4541
 4542                            (
 4543                                comment_delimiter,
 4544                                doc_delimiter,
 4545                                insert_extra_newline,
 4546                                indent_on_newline,
 4547                                indent_on_extra_newline,
 4548                            )
 4549                        } else {
 4550                            (
 4551                                None,
 4552                                None,
 4553                                false,
 4554                                IndentSize::default(),
 4555                                IndentSize::default(),
 4556                            )
 4557                        };
 4558
 4559                        let prevent_auto_indent = doc_delimiter.is_some();
 4560                        let delimiter = comment_delimiter.or(doc_delimiter);
 4561
 4562                        let capacity_for_delimiter =
 4563                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4564                        let mut new_text = String::with_capacity(
 4565                            1 + capacity_for_delimiter
 4566                                + existing_indent.len as usize
 4567                                + indent_on_newline.len as usize
 4568                                + indent_on_extra_newline.len as usize,
 4569                        );
 4570                        new_text.push('\n');
 4571                        new_text.extend(existing_indent.chars());
 4572                        new_text.extend(indent_on_newline.chars());
 4573
 4574                        if let Some(delimiter) = &delimiter {
 4575                            new_text.push_str(delimiter);
 4576                        }
 4577
 4578                        if insert_extra_newline {
 4579                            new_text.push('\n');
 4580                            new_text.extend(existing_indent.chars());
 4581                            new_text.extend(indent_on_extra_newline.chars());
 4582                        }
 4583
 4584                        let anchor = buffer.anchor_after(end);
 4585                        let new_selection = selection.map(|_| anchor);
 4586                        (
 4587                            ((start..end, new_text), prevent_auto_indent),
 4588                            (insert_extra_newline, new_selection),
 4589                        )
 4590                    })
 4591                    .unzip()
 4592            };
 4593
 4594            let mut auto_indent_edits = Vec::new();
 4595            let mut edits = Vec::new();
 4596            for (edit, prevent_auto_indent) in edits_with_flags {
 4597                if prevent_auto_indent {
 4598                    edits.push(edit);
 4599                } else {
 4600                    auto_indent_edits.push(edit);
 4601                }
 4602            }
 4603            if !edits.is_empty() {
 4604                this.edit(edits, cx);
 4605            }
 4606            if !auto_indent_edits.is_empty() {
 4607                this.edit_with_autoindent(auto_indent_edits, cx);
 4608            }
 4609
 4610            let buffer = this.buffer.read(cx).snapshot(cx);
 4611            let new_selections = selection_info
 4612                .into_iter()
 4613                .map(|(extra_newline_inserted, new_selection)| {
 4614                    let mut cursor = new_selection.end.to_point(&buffer);
 4615                    if extra_newline_inserted {
 4616                        cursor.row -= 1;
 4617                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4618                    }
 4619                    new_selection.map(|_| cursor)
 4620                })
 4621                .collect();
 4622
 4623            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4624            this.refresh_inline_completion(true, false, window, cx);
 4625        });
 4626    }
 4627
 4628    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4629        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4630
 4631        let buffer = self.buffer.read(cx);
 4632        let snapshot = buffer.snapshot(cx);
 4633
 4634        let mut edits = Vec::new();
 4635        let mut rows = Vec::new();
 4636
 4637        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4638            let cursor = selection.head();
 4639            let row = cursor.row;
 4640
 4641            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4642
 4643            let newline = "\n".to_string();
 4644            edits.push((start_of_line..start_of_line, newline));
 4645
 4646            rows.push(row + rows_inserted as u32);
 4647        }
 4648
 4649        self.transact(window, cx, |editor, window, cx| {
 4650            editor.edit(edits, cx);
 4651
 4652            editor.change_selections(Default::default(), window, cx, |s| {
 4653                let mut index = 0;
 4654                s.move_cursors_with(|map, _, _| {
 4655                    let row = rows[index];
 4656                    index += 1;
 4657
 4658                    let point = Point::new(row, 0);
 4659                    let boundary = map.next_line_boundary(point).1;
 4660                    let clipped = map.clip_point(boundary, Bias::Left);
 4661
 4662                    (clipped, SelectionGoal::None)
 4663                });
 4664            });
 4665
 4666            let mut indent_edits = Vec::new();
 4667            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4668            for row in rows {
 4669                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4670                for (row, indent) in indents {
 4671                    if indent.len == 0 {
 4672                        continue;
 4673                    }
 4674
 4675                    let text = match indent.kind {
 4676                        IndentKind::Space => " ".repeat(indent.len as usize),
 4677                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4678                    };
 4679                    let point = Point::new(row.0, 0);
 4680                    indent_edits.push((point..point, text));
 4681                }
 4682            }
 4683            editor.edit(indent_edits, cx);
 4684        });
 4685    }
 4686
 4687    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4688        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4689
 4690        let buffer = self.buffer.read(cx);
 4691        let snapshot = buffer.snapshot(cx);
 4692
 4693        let mut edits = Vec::new();
 4694        let mut rows = Vec::new();
 4695        let mut rows_inserted = 0;
 4696
 4697        for selection in self.selections.all_adjusted(cx) {
 4698            let cursor = selection.head();
 4699            let row = cursor.row;
 4700
 4701            let point = Point::new(row + 1, 0);
 4702            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4703
 4704            let newline = "\n".to_string();
 4705            edits.push((start_of_line..start_of_line, newline));
 4706
 4707            rows_inserted += 1;
 4708            rows.push(row + rows_inserted);
 4709        }
 4710
 4711        self.transact(window, cx, |editor, window, cx| {
 4712            editor.edit(edits, cx);
 4713
 4714            editor.change_selections(Default::default(), window, cx, |s| {
 4715                let mut index = 0;
 4716                s.move_cursors_with(|map, _, _| {
 4717                    let row = rows[index];
 4718                    index += 1;
 4719
 4720                    let point = Point::new(row, 0);
 4721                    let boundary = map.next_line_boundary(point).1;
 4722                    let clipped = map.clip_point(boundary, Bias::Left);
 4723
 4724                    (clipped, SelectionGoal::None)
 4725                });
 4726            });
 4727
 4728            let mut indent_edits = Vec::new();
 4729            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4730            for row in rows {
 4731                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4732                for (row, indent) in indents {
 4733                    if indent.len == 0 {
 4734                        continue;
 4735                    }
 4736
 4737                    let text = match indent.kind {
 4738                        IndentKind::Space => " ".repeat(indent.len as usize),
 4739                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4740                    };
 4741                    let point = Point::new(row.0, 0);
 4742                    indent_edits.push((point..point, text));
 4743                }
 4744            }
 4745            editor.edit(indent_edits, cx);
 4746        });
 4747    }
 4748
 4749    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4750        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4751            original_indent_columns: Vec::new(),
 4752        });
 4753        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4754    }
 4755
 4756    fn insert_with_autoindent_mode(
 4757        &mut self,
 4758        text: &str,
 4759        autoindent_mode: Option<AutoindentMode>,
 4760        window: &mut Window,
 4761        cx: &mut Context<Self>,
 4762    ) {
 4763        if self.read_only(cx) {
 4764            return;
 4765        }
 4766
 4767        let text: Arc<str> = text.into();
 4768        self.transact(window, cx, |this, window, cx| {
 4769            let old_selections = this.selections.all_adjusted(cx);
 4770            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4771                let anchors = {
 4772                    let snapshot = buffer.read(cx);
 4773                    old_selections
 4774                        .iter()
 4775                        .map(|s| {
 4776                            let anchor = snapshot.anchor_after(s.head());
 4777                            s.map(|_| anchor)
 4778                        })
 4779                        .collect::<Vec<_>>()
 4780                };
 4781                buffer.edit(
 4782                    old_selections
 4783                        .iter()
 4784                        .map(|s| (s.start..s.end, text.clone())),
 4785                    autoindent_mode,
 4786                    cx,
 4787                );
 4788                anchors
 4789            });
 4790
 4791            this.change_selections(Default::default(), window, cx, |s| {
 4792                s.select_anchors(selection_anchors);
 4793            });
 4794
 4795            cx.notify();
 4796        });
 4797    }
 4798
 4799    fn trigger_completion_on_input(
 4800        &mut self,
 4801        text: &str,
 4802        trigger_in_words: bool,
 4803        window: &mut Window,
 4804        cx: &mut Context<Self>,
 4805    ) {
 4806        let completions_source = self
 4807            .context_menu
 4808            .borrow()
 4809            .as_ref()
 4810            .and_then(|menu| match menu {
 4811                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4812                CodeContextMenu::CodeActions(_) => None,
 4813            });
 4814
 4815        match completions_source {
 4816            Some(CompletionsMenuSource::Words) => {
 4817                self.show_word_completions(&ShowWordCompletions, window, cx)
 4818            }
 4819            Some(CompletionsMenuSource::Normal)
 4820            | Some(CompletionsMenuSource::SnippetChoices)
 4821            | None
 4822                if self.is_completion_trigger(
 4823                    text,
 4824                    trigger_in_words,
 4825                    completions_source.is_some(),
 4826                    cx,
 4827                ) =>
 4828            {
 4829                self.show_completions(
 4830                    &ShowCompletions {
 4831                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4832                    },
 4833                    window,
 4834                    cx,
 4835                )
 4836            }
 4837            _ => {
 4838                self.hide_context_menu(window, cx);
 4839            }
 4840        }
 4841    }
 4842
 4843    fn is_completion_trigger(
 4844        &self,
 4845        text: &str,
 4846        trigger_in_words: bool,
 4847        menu_is_open: bool,
 4848        cx: &mut Context<Self>,
 4849    ) -> bool {
 4850        let position = self.selections.newest_anchor().head();
 4851        let multibuffer = self.buffer.read(cx);
 4852        let Some(buffer) = position
 4853            .buffer_id
 4854            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4855        else {
 4856            return false;
 4857        };
 4858
 4859        if let Some(completion_provider) = &self.completion_provider {
 4860            completion_provider.is_completion_trigger(
 4861                &buffer,
 4862                position.text_anchor,
 4863                text,
 4864                trigger_in_words,
 4865                menu_is_open,
 4866                cx,
 4867            )
 4868        } else {
 4869            false
 4870        }
 4871    }
 4872
 4873    /// If any empty selections is touching the start of its innermost containing autoclose
 4874    /// region, expand it to select the brackets.
 4875    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4876        let selections = self.selections.all::<usize>(cx);
 4877        let buffer = self.buffer.read(cx).read(cx);
 4878        let new_selections = self
 4879            .selections_with_autoclose_regions(selections, &buffer)
 4880            .map(|(mut selection, region)| {
 4881                if !selection.is_empty() {
 4882                    return selection;
 4883                }
 4884
 4885                if let Some(region) = region {
 4886                    let mut range = region.range.to_offset(&buffer);
 4887                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4888                        range.start -= region.pair.start.len();
 4889                        if buffer.contains_str_at(range.start, &region.pair.start)
 4890                            && buffer.contains_str_at(range.end, &region.pair.end)
 4891                        {
 4892                            range.end += region.pair.end.len();
 4893                            selection.start = range.start;
 4894                            selection.end = range.end;
 4895
 4896                            return selection;
 4897                        }
 4898                    }
 4899                }
 4900
 4901                let always_treat_brackets_as_autoclosed = buffer
 4902                    .language_settings_at(selection.start, cx)
 4903                    .always_treat_brackets_as_autoclosed;
 4904
 4905                if !always_treat_brackets_as_autoclosed {
 4906                    return selection;
 4907                }
 4908
 4909                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4910                    for (pair, enabled) in scope.brackets() {
 4911                        if !enabled || !pair.close {
 4912                            continue;
 4913                        }
 4914
 4915                        if buffer.contains_str_at(selection.start, &pair.end) {
 4916                            let pair_start_len = pair.start.len();
 4917                            if buffer.contains_str_at(
 4918                                selection.start.saturating_sub(pair_start_len),
 4919                                &pair.start,
 4920                            ) {
 4921                                selection.start -= pair_start_len;
 4922                                selection.end += pair.end.len();
 4923
 4924                                return selection;
 4925                            }
 4926                        }
 4927                    }
 4928                }
 4929
 4930                selection
 4931            })
 4932            .collect();
 4933
 4934        drop(buffer);
 4935        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 4936            selections.select(new_selections)
 4937        });
 4938    }
 4939
 4940    /// Iterate the given selections, and for each one, find the smallest surrounding
 4941    /// autoclose region. This uses the ordering of the selections and the autoclose
 4942    /// regions to avoid repeated comparisons.
 4943    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4944        &'a self,
 4945        selections: impl IntoIterator<Item = Selection<D>>,
 4946        buffer: &'a MultiBufferSnapshot,
 4947    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4948        let mut i = 0;
 4949        let mut regions = self.autoclose_regions.as_slice();
 4950        selections.into_iter().map(move |selection| {
 4951            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4952
 4953            let mut enclosing = None;
 4954            while let Some(pair_state) = regions.get(i) {
 4955                if pair_state.range.end.to_offset(buffer) < range.start {
 4956                    regions = &regions[i + 1..];
 4957                    i = 0;
 4958                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4959                    break;
 4960                } else {
 4961                    if pair_state.selection_id == selection.id {
 4962                        enclosing = Some(pair_state);
 4963                    }
 4964                    i += 1;
 4965                }
 4966            }
 4967
 4968            (selection, enclosing)
 4969        })
 4970    }
 4971
 4972    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 4973    fn invalidate_autoclose_regions(
 4974        &mut self,
 4975        mut selections: &[Selection<Anchor>],
 4976        buffer: &MultiBufferSnapshot,
 4977    ) {
 4978        self.autoclose_regions.retain(|state| {
 4979            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 4980                return false;
 4981            }
 4982
 4983            let mut i = 0;
 4984            while let Some(selection) = selections.get(i) {
 4985                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4986                    selections = &selections[1..];
 4987                    continue;
 4988                }
 4989                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4990                    break;
 4991                }
 4992                if selection.id == state.selection_id {
 4993                    return true;
 4994                } else {
 4995                    i += 1;
 4996                }
 4997            }
 4998            false
 4999        });
 5000    }
 5001
 5002    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5003        let offset = position.to_offset(buffer);
 5004        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5005        if offset > word_range.start && kind == Some(CharKind::Word) {
 5006            Some(
 5007                buffer
 5008                    .text_for_range(word_range.start..offset)
 5009                    .collect::<String>(),
 5010            )
 5011        } else {
 5012            None
 5013        }
 5014    }
 5015
 5016    pub fn toggle_inline_values(
 5017        &mut self,
 5018        _: &ToggleInlineValues,
 5019        _: &mut Window,
 5020        cx: &mut Context<Self>,
 5021    ) {
 5022        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5023
 5024        self.refresh_inline_values(cx);
 5025    }
 5026
 5027    pub fn toggle_inlay_hints(
 5028        &mut self,
 5029        _: &ToggleInlayHints,
 5030        _: &mut Window,
 5031        cx: &mut Context<Self>,
 5032    ) {
 5033        self.refresh_inlay_hints(
 5034            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5035            cx,
 5036        );
 5037    }
 5038
 5039    pub fn inlay_hints_enabled(&self) -> bool {
 5040        self.inlay_hint_cache.enabled
 5041    }
 5042
 5043    pub fn inline_values_enabled(&self) -> bool {
 5044        self.inline_value_cache.enabled
 5045    }
 5046
 5047    #[cfg(any(test, feature = "test-support"))]
 5048    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5049        self.display_map
 5050            .read(cx)
 5051            .current_inlays()
 5052            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5053            .cloned()
 5054            .collect()
 5055    }
 5056
 5057    #[cfg(any(test, feature = "test-support"))]
 5058    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5059        self.display_map
 5060            .read(cx)
 5061            .current_inlays()
 5062            .cloned()
 5063            .collect()
 5064    }
 5065
 5066    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5067        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5068            return;
 5069        }
 5070
 5071        let reason_description = reason.description();
 5072        let ignore_debounce = matches!(
 5073            reason,
 5074            InlayHintRefreshReason::SettingsChange(_)
 5075                | InlayHintRefreshReason::Toggle(_)
 5076                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5077                | InlayHintRefreshReason::ModifiersChanged(_)
 5078        );
 5079        let (invalidate_cache, required_languages) = match reason {
 5080            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5081                match self.inlay_hint_cache.modifiers_override(enabled) {
 5082                    Some(enabled) => {
 5083                        if enabled {
 5084                            (InvalidationStrategy::RefreshRequested, None)
 5085                        } else {
 5086                            self.splice_inlays(
 5087                                &self
 5088                                    .visible_inlay_hints(cx)
 5089                                    .iter()
 5090                                    .map(|inlay| inlay.id)
 5091                                    .collect::<Vec<InlayId>>(),
 5092                                Vec::new(),
 5093                                cx,
 5094                            );
 5095                            return;
 5096                        }
 5097                    }
 5098                    None => return,
 5099                }
 5100            }
 5101            InlayHintRefreshReason::Toggle(enabled) => {
 5102                if self.inlay_hint_cache.toggle(enabled) {
 5103                    if enabled {
 5104                        (InvalidationStrategy::RefreshRequested, None)
 5105                    } else {
 5106                        self.splice_inlays(
 5107                            &self
 5108                                .visible_inlay_hints(cx)
 5109                                .iter()
 5110                                .map(|inlay| inlay.id)
 5111                                .collect::<Vec<InlayId>>(),
 5112                            Vec::new(),
 5113                            cx,
 5114                        );
 5115                        return;
 5116                    }
 5117                } else {
 5118                    return;
 5119                }
 5120            }
 5121            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5122                match self.inlay_hint_cache.update_settings(
 5123                    &self.buffer,
 5124                    new_settings,
 5125                    self.visible_inlay_hints(cx),
 5126                    cx,
 5127                ) {
 5128                    ControlFlow::Break(Some(InlaySplice {
 5129                        to_remove,
 5130                        to_insert,
 5131                    })) => {
 5132                        self.splice_inlays(&to_remove, to_insert, cx);
 5133                        return;
 5134                    }
 5135                    ControlFlow::Break(None) => return,
 5136                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5137                }
 5138            }
 5139            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5140                if let Some(InlaySplice {
 5141                    to_remove,
 5142                    to_insert,
 5143                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5144                {
 5145                    self.splice_inlays(&to_remove, to_insert, cx);
 5146                }
 5147                self.display_map.update(cx, |display_map, _| {
 5148                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5149                });
 5150                return;
 5151            }
 5152            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5153            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5154                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5155            }
 5156            InlayHintRefreshReason::RefreshRequested => {
 5157                (InvalidationStrategy::RefreshRequested, None)
 5158            }
 5159        };
 5160
 5161        if let Some(InlaySplice {
 5162            to_remove,
 5163            to_insert,
 5164        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5165            reason_description,
 5166            self.visible_excerpts(required_languages.as_ref(), cx),
 5167            invalidate_cache,
 5168            ignore_debounce,
 5169            cx,
 5170        ) {
 5171            self.splice_inlays(&to_remove, to_insert, cx);
 5172        }
 5173    }
 5174
 5175    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5176        self.display_map
 5177            .read(cx)
 5178            .current_inlays()
 5179            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5180            .cloned()
 5181            .collect()
 5182    }
 5183
 5184    pub fn visible_excerpts(
 5185        &self,
 5186        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5187        cx: &mut Context<Editor>,
 5188    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5189        let Some(project) = self.project.as_ref() else {
 5190            return HashMap::default();
 5191        };
 5192        let project = project.read(cx);
 5193        let multi_buffer = self.buffer().read(cx);
 5194        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5195        let multi_buffer_visible_start = self
 5196            .scroll_manager
 5197            .anchor()
 5198            .anchor
 5199            .to_point(&multi_buffer_snapshot);
 5200        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5201            multi_buffer_visible_start
 5202                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5203            Bias::Left,
 5204        );
 5205        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5206        multi_buffer_snapshot
 5207            .range_to_buffer_ranges(multi_buffer_visible_range)
 5208            .into_iter()
 5209            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5210            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5211                let buffer_file = project::File::from_dyn(buffer.file())?;
 5212                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5213                let worktree_entry = buffer_worktree
 5214                    .read(cx)
 5215                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5216                if worktree_entry.is_ignored {
 5217                    return None;
 5218                }
 5219
 5220                let language = buffer.language()?;
 5221                if let Some(restrict_to_languages) = restrict_to_languages {
 5222                    if !restrict_to_languages.contains(language) {
 5223                        return None;
 5224                    }
 5225                }
 5226                Some((
 5227                    excerpt_id,
 5228                    (
 5229                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5230                        buffer.version().clone(),
 5231                        excerpt_visible_range,
 5232                    ),
 5233                ))
 5234            })
 5235            .collect()
 5236    }
 5237
 5238    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5239        TextLayoutDetails {
 5240            text_system: window.text_system().clone(),
 5241            editor_style: self.style.clone().unwrap(),
 5242            rem_size: window.rem_size(),
 5243            scroll_anchor: self.scroll_manager.anchor(),
 5244            visible_rows: self.visible_line_count(),
 5245            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5246        }
 5247    }
 5248
 5249    pub fn splice_inlays(
 5250        &self,
 5251        to_remove: &[InlayId],
 5252        to_insert: Vec<Inlay>,
 5253        cx: &mut Context<Self>,
 5254    ) {
 5255        self.display_map.update(cx, |display_map, cx| {
 5256            display_map.splice_inlays(to_remove, to_insert, cx)
 5257        });
 5258        cx.notify();
 5259    }
 5260
 5261    fn trigger_on_type_formatting(
 5262        &self,
 5263        input: String,
 5264        window: &mut Window,
 5265        cx: &mut Context<Self>,
 5266    ) -> Option<Task<Result<()>>> {
 5267        if input.len() != 1 {
 5268            return None;
 5269        }
 5270
 5271        let project = self.project.as_ref()?;
 5272        let position = self.selections.newest_anchor().head();
 5273        let (buffer, buffer_position) = self
 5274            .buffer
 5275            .read(cx)
 5276            .text_anchor_for_position(position, cx)?;
 5277
 5278        let settings = language_settings::language_settings(
 5279            buffer
 5280                .read(cx)
 5281                .language_at(buffer_position)
 5282                .map(|l| l.name()),
 5283            buffer.read(cx).file(),
 5284            cx,
 5285        );
 5286        if !settings.use_on_type_format {
 5287            return None;
 5288        }
 5289
 5290        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5291        // hence we do LSP request & edit on host side only — add formats to host's history.
 5292        let push_to_lsp_host_history = true;
 5293        // If this is not the host, append its history with new edits.
 5294        let push_to_client_history = project.read(cx).is_via_collab();
 5295
 5296        let on_type_formatting = project.update(cx, |project, cx| {
 5297            project.on_type_format(
 5298                buffer.clone(),
 5299                buffer_position,
 5300                input,
 5301                push_to_lsp_host_history,
 5302                cx,
 5303            )
 5304        });
 5305        Some(cx.spawn_in(window, async move |editor, cx| {
 5306            if let Some(transaction) = on_type_formatting.await? {
 5307                if push_to_client_history {
 5308                    buffer
 5309                        .update(cx, |buffer, _| {
 5310                            buffer.push_transaction(transaction, Instant::now());
 5311                            buffer.finalize_last_transaction();
 5312                        })
 5313                        .ok();
 5314                }
 5315                editor.update(cx, |editor, cx| {
 5316                    editor.refresh_document_highlights(cx);
 5317                })?;
 5318            }
 5319            Ok(())
 5320        }))
 5321    }
 5322
 5323    pub fn show_word_completions(
 5324        &mut self,
 5325        _: &ShowWordCompletions,
 5326        window: &mut Window,
 5327        cx: &mut Context<Self>,
 5328    ) {
 5329        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5330    }
 5331
 5332    pub fn show_completions(
 5333        &mut self,
 5334        options: &ShowCompletions,
 5335        window: &mut Window,
 5336        cx: &mut Context<Self>,
 5337    ) {
 5338        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5339    }
 5340
 5341    fn open_or_update_completions_menu(
 5342        &mut self,
 5343        requested_source: Option<CompletionsMenuSource>,
 5344        trigger: Option<&str>,
 5345        window: &mut Window,
 5346        cx: &mut Context<Self>,
 5347    ) {
 5348        if self.pending_rename.is_some() {
 5349            return;
 5350        }
 5351
 5352        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5353
 5354        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5355        // inserted and selected. To handle that case, the start of the selection is used so that
 5356        // the menu starts with all choices.
 5357        let position = self
 5358            .selections
 5359            .newest_anchor()
 5360            .start
 5361            .bias_right(&multibuffer_snapshot);
 5362        if position.diff_base_anchor.is_some() {
 5363            return;
 5364        }
 5365        let (buffer, buffer_position) =
 5366            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5367                output
 5368            } else {
 5369                return;
 5370            };
 5371        let buffer_snapshot = buffer.read(cx).snapshot();
 5372
 5373        let query: Option<Arc<String>> =
 5374            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5375
 5376        drop(multibuffer_snapshot);
 5377
 5378        let provider = match requested_source {
 5379            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5380            Some(CompletionsMenuSource::Words) => None,
 5381            Some(CompletionsMenuSource::SnippetChoices) => {
 5382                log::error!("bug: SnippetChoices requested_source is not handled");
 5383                None
 5384            }
 5385        };
 5386
 5387        let sort_completions = provider
 5388            .as_ref()
 5389            .map_or(false, |provider| provider.sort_completions());
 5390
 5391        let filter_completions = provider
 5392            .as_ref()
 5393            .map_or(true, |provider| provider.filter_completions());
 5394
 5395        let trigger_kind = match trigger {
 5396            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5397                CompletionTriggerKind::TRIGGER_CHARACTER
 5398            }
 5399            _ => CompletionTriggerKind::INVOKED,
 5400        };
 5401        let completion_context = CompletionContext {
 5402            trigger_character: trigger.and_then(|trigger| {
 5403                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5404                    Some(String::from(trigger))
 5405                } else {
 5406                    None
 5407                }
 5408            }),
 5409            trigger_kind,
 5410        };
 5411
 5412        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5413        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5414        // involve trigger chars, so this is skipped in that case.
 5415        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5416        {
 5417            let menu_is_open = matches!(
 5418                self.context_menu.borrow().as_ref(),
 5419                Some(CodeContextMenu::Completions(_))
 5420            );
 5421            if menu_is_open {
 5422                self.hide_context_menu(window, cx);
 5423            }
 5424        }
 5425
 5426        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5427            if filter_completions {
 5428                menu.filter(query.clone(), provider.clone(), window, cx);
 5429            }
 5430            // When `is_incomplete` is false, no need to re-query completions when the current query
 5431            // is a suffix of the initial query.
 5432            if !menu.is_incomplete {
 5433                // If the new query is a suffix of the old query (typing more characters) and
 5434                // the previous result was complete, the existing completions can be filtered.
 5435                //
 5436                // Note that this is always true for snippet completions.
 5437                let query_matches = match (&menu.initial_query, &query) {
 5438                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5439                    (None, _) => true,
 5440                    _ => false,
 5441                };
 5442                if query_matches {
 5443                    let position_matches = if menu.initial_position == position {
 5444                        true
 5445                    } else {
 5446                        let snapshot = self.buffer.read(cx).read(cx);
 5447                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5448                    };
 5449                    if position_matches {
 5450                        return;
 5451                    }
 5452                }
 5453            }
 5454        };
 5455
 5456        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5457            buffer_snapshot.surrounding_word(buffer_position, false)
 5458        {
 5459            let word_to_exclude = buffer_snapshot
 5460                .text_for_range(word_range.clone())
 5461                .collect::<String>();
 5462            (
 5463                buffer_snapshot.anchor_before(word_range.start)
 5464                    ..buffer_snapshot.anchor_after(buffer_position),
 5465                Some(word_to_exclude),
 5466            )
 5467        } else {
 5468            (buffer_position..buffer_position, None)
 5469        };
 5470
 5471        let language = buffer_snapshot
 5472            .language_at(buffer_position)
 5473            .map(|language| language.name());
 5474
 5475        let completion_settings =
 5476            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5477
 5478        let show_completion_documentation = buffer_snapshot
 5479            .settings_at(buffer_position, cx)
 5480            .show_completion_documentation;
 5481
 5482        // The document can be large, so stay in reasonable bounds when searching for words,
 5483        // otherwise completion pop-up might be slow to appear.
 5484        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5485        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5486        let min_word_search = buffer_snapshot.clip_point(
 5487            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5488            Bias::Left,
 5489        );
 5490        let max_word_search = buffer_snapshot.clip_point(
 5491            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5492            Bias::Right,
 5493        );
 5494        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5495            ..buffer_snapshot.point_to_offset(max_word_search);
 5496
 5497        let skip_digits = query
 5498            .as_ref()
 5499            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5500
 5501        let (mut words, provider_responses) = match &provider {
 5502            Some(provider) => {
 5503                let provider_responses = provider.completions(
 5504                    position.excerpt_id,
 5505                    &buffer,
 5506                    buffer_position,
 5507                    completion_context,
 5508                    window,
 5509                    cx,
 5510                );
 5511
 5512                let words = match completion_settings.words {
 5513                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5514                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5515                        .background_spawn(async move {
 5516                            buffer_snapshot.words_in_range(WordsQuery {
 5517                                fuzzy_contents: None,
 5518                                range: word_search_range,
 5519                                skip_digits,
 5520                            })
 5521                        }),
 5522                };
 5523
 5524                (words, provider_responses)
 5525            }
 5526            None => (
 5527                cx.background_spawn(async move {
 5528                    buffer_snapshot.words_in_range(WordsQuery {
 5529                        fuzzy_contents: None,
 5530                        range: word_search_range,
 5531                        skip_digits,
 5532                    })
 5533                }),
 5534                Task::ready(Ok(Vec::new())),
 5535            ),
 5536        };
 5537
 5538        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5539
 5540        let id = post_inc(&mut self.next_completion_id);
 5541        let task = cx.spawn_in(window, async move |editor, cx| {
 5542            let Ok(()) = editor.update(cx, |this, _| {
 5543                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5544            }) else {
 5545                return;
 5546            };
 5547
 5548            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5549            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5550            let mut completions = Vec::new();
 5551            let mut is_incomplete = false;
 5552            if let Some(provider_responses) = provider_responses.await.log_err() {
 5553                if !provider_responses.is_empty() {
 5554                    for response in provider_responses {
 5555                        completions.extend(response.completions);
 5556                        is_incomplete = is_incomplete || response.is_incomplete;
 5557                    }
 5558                    if completion_settings.words == WordsCompletionMode::Fallback {
 5559                        words = Task::ready(BTreeMap::default());
 5560                    }
 5561                }
 5562            }
 5563
 5564            let mut words = words.await;
 5565            if let Some(word_to_exclude) = &word_to_exclude {
 5566                words.remove(word_to_exclude);
 5567            }
 5568            for lsp_completion in &completions {
 5569                words.remove(&lsp_completion.new_text);
 5570            }
 5571            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5572                replace_range: word_replace_range.clone(),
 5573                new_text: word.clone(),
 5574                label: CodeLabel::plain(word, None),
 5575                icon_path: None,
 5576                documentation: None,
 5577                source: CompletionSource::BufferWord {
 5578                    word_range,
 5579                    resolved: false,
 5580                },
 5581                insert_text_mode: Some(InsertTextMode::AS_IS),
 5582                confirm: None,
 5583            }));
 5584
 5585            let menu = if completions.is_empty() {
 5586                None
 5587            } else {
 5588                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5589                    let languages = editor
 5590                        .workspace
 5591                        .as_ref()
 5592                        .and_then(|(workspace, _)| workspace.upgrade())
 5593                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5594                    let menu = CompletionsMenu::new(
 5595                        id,
 5596                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5597                        sort_completions,
 5598                        show_completion_documentation,
 5599                        position,
 5600                        query.clone(),
 5601                        is_incomplete,
 5602                        buffer.clone(),
 5603                        completions.into(),
 5604                        snippet_sort_order,
 5605                        languages,
 5606                        language,
 5607                        cx,
 5608                    );
 5609
 5610                    let query = if filter_completions { query } else { None };
 5611                    let matches_task = if let Some(query) = query {
 5612                        menu.do_async_filtering(query, cx)
 5613                    } else {
 5614                        Task::ready(menu.unfiltered_matches())
 5615                    };
 5616                    (menu, matches_task)
 5617                }) else {
 5618                    return;
 5619                };
 5620
 5621                let matches = matches_task.await;
 5622
 5623                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5624                    // Newer menu already set, so exit.
 5625                    match editor.context_menu.borrow().as_ref() {
 5626                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5627                            if prev_menu.id > id {
 5628                                return;
 5629                            }
 5630                        }
 5631                        _ => {}
 5632                    };
 5633
 5634                    // Only valid to take prev_menu because it the new menu is immediately set
 5635                    // below, or the menu is hidden.
 5636                    match editor.context_menu.borrow_mut().take() {
 5637                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5638                            let position_matches =
 5639                                if prev_menu.initial_position == menu.initial_position {
 5640                                    true
 5641                                } else {
 5642                                    let snapshot = editor.buffer.read(cx).read(cx);
 5643                                    prev_menu.initial_position.to_offset(&snapshot)
 5644                                        == menu.initial_position.to_offset(&snapshot)
 5645                                };
 5646                            if position_matches {
 5647                                // Preserve markdown cache before `set_filter_results` because it will
 5648                                // try to populate the documentation cache.
 5649                                menu.preserve_markdown_cache(prev_menu);
 5650                            }
 5651                        }
 5652                        _ => {}
 5653                    };
 5654
 5655                    menu.set_filter_results(matches, provider, window, cx);
 5656                }) else {
 5657                    return;
 5658                };
 5659
 5660                menu.visible().then_some(menu)
 5661            };
 5662
 5663            editor
 5664                .update_in(cx, |editor, window, cx| {
 5665                    if editor.focus_handle.is_focused(window) {
 5666                        if let Some(menu) = menu {
 5667                            *editor.context_menu.borrow_mut() =
 5668                                Some(CodeContextMenu::Completions(menu));
 5669
 5670                            crate::hover_popover::hide_hover(editor, cx);
 5671                            if editor.show_edit_predictions_in_menu() {
 5672                                editor.update_visible_inline_completion(window, cx);
 5673                            } else {
 5674                                editor.discard_inline_completion(false, cx);
 5675                            }
 5676
 5677                            cx.notify();
 5678                            return;
 5679                        }
 5680                    }
 5681
 5682                    if editor.completion_tasks.len() <= 1 {
 5683                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5684                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5685                        // If it was already hidden and we don't show inline completions in the menu, we should
 5686                        // also show the inline-completion when available.
 5687                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5688                            editor.update_visible_inline_completion(window, cx);
 5689                        }
 5690                    }
 5691                })
 5692                .ok();
 5693        });
 5694
 5695        self.completion_tasks.push((id, task));
 5696    }
 5697
 5698    #[cfg(feature = "test-support")]
 5699    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5700        let menu = self.context_menu.borrow();
 5701        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5702            let completions = menu.completions.borrow();
 5703            Some(completions.to_vec())
 5704        } else {
 5705            None
 5706        }
 5707    }
 5708
 5709    pub fn with_completions_menu_matching_id<R>(
 5710        &self,
 5711        id: CompletionId,
 5712        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5713    ) -> R {
 5714        let mut context_menu = self.context_menu.borrow_mut();
 5715        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5716            return f(None);
 5717        };
 5718        if completions_menu.id != id {
 5719            return f(None);
 5720        }
 5721        f(Some(completions_menu))
 5722    }
 5723
 5724    pub fn confirm_completion(
 5725        &mut self,
 5726        action: &ConfirmCompletion,
 5727        window: &mut Window,
 5728        cx: &mut Context<Self>,
 5729    ) -> Option<Task<Result<()>>> {
 5730        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5731        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5732    }
 5733
 5734    pub fn confirm_completion_insert(
 5735        &mut self,
 5736        _: &ConfirmCompletionInsert,
 5737        window: &mut Window,
 5738        cx: &mut Context<Self>,
 5739    ) -> Option<Task<Result<()>>> {
 5740        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5741        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5742    }
 5743
 5744    pub fn confirm_completion_replace(
 5745        &mut self,
 5746        _: &ConfirmCompletionReplace,
 5747        window: &mut Window,
 5748        cx: &mut Context<Self>,
 5749    ) -> Option<Task<Result<()>>> {
 5750        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5751        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5752    }
 5753
 5754    pub fn compose_completion(
 5755        &mut self,
 5756        action: &ComposeCompletion,
 5757        window: &mut Window,
 5758        cx: &mut Context<Self>,
 5759    ) -> Option<Task<Result<()>>> {
 5760        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5761        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5762    }
 5763
 5764    fn do_completion(
 5765        &mut self,
 5766        item_ix: Option<usize>,
 5767        intent: CompletionIntent,
 5768        window: &mut Window,
 5769        cx: &mut Context<Editor>,
 5770    ) -> Option<Task<Result<()>>> {
 5771        use language::ToOffset as _;
 5772
 5773        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5774        else {
 5775            return None;
 5776        };
 5777
 5778        let candidate_id = {
 5779            let entries = completions_menu.entries.borrow();
 5780            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5781            if self.show_edit_predictions_in_menu() {
 5782                self.discard_inline_completion(true, cx);
 5783            }
 5784            mat.candidate_id
 5785        };
 5786
 5787        let completion = completions_menu
 5788            .completions
 5789            .borrow()
 5790            .get(candidate_id)?
 5791            .clone();
 5792        cx.stop_propagation();
 5793
 5794        let buffer_handle = completions_menu.buffer.clone();
 5795
 5796        let CompletionEdit {
 5797            new_text,
 5798            snippet,
 5799            replace_range,
 5800        } = process_completion_for_edit(
 5801            &completion,
 5802            intent,
 5803            &buffer_handle,
 5804            &completions_menu.initial_position.text_anchor,
 5805            cx,
 5806        );
 5807
 5808        let buffer = buffer_handle.read(cx);
 5809        let snapshot = self.buffer.read(cx).snapshot(cx);
 5810        let newest_anchor = self.selections.newest_anchor();
 5811        let replace_range_multibuffer = {
 5812            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5813            let multibuffer_anchor = snapshot
 5814                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5815                .unwrap()
 5816                ..snapshot
 5817                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5818                    .unwrap();
 5819            multibuffer_anchor.start.to_offset(&snapshot)
 5820                ..multibuffer_anchor.end.to_offset(&snapshot)
 5821        };
 5822        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5823            return None;
 5824        }
 5825
 5826        let old_text = buffer
 5827            .text_for_range(replace_range.clone())
 5828            .collect::<String>();
 5829        let lookbehind = newest_anchor
 5830            .start
 5831            .text_anchor
 5832            .to_offset(buffer)
 5833            .saturating_sub(replace_range.start);
 5834        let lookahead = replace_range
 5835            .end
 5836            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5837        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5838        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5839
 5840        let selections = self.selections.all::<usize>(cx);
 5841        let mut ranges = Vec::new();
 5842        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5843
 5844        for selection in &selections {
 5845            let range = if selection.id == newest_anchor.id {
 5846                replace_range_multibuffer.clone()
 5847            } else {
 5848                let mut range = selection.range();
 5849
 5850                // if prefix is present, don't duplicate it
 5851                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5852                    range.start = range.start.saturating_sub(lookbehind);
 5853
 5854                    // if suffix is also present, mimic the newest cursor and replace it
 5855                    if selection.id != newest_anchor.id
 5856                        && snapshot.contains_str_at(range.end, suffix)
 5857                    {
 5858                        range.end += lookahead;
 5859                    }
 5860                }
 5861                range
 5862            };
 5863
 5864            ranges.push(range.clone());
 5865
 5866            if !self.linked_edit_ranges.is_empty() {
 5867                let start_anchor = snapshot.anchor_before(range.start);
 5868                let end_anchor = snapshot.anchor_after(range.end);
 5869                if let Some(ranges) = self
 5870                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5871                {
 5872                    for (buffer, edits) in ranges {
 5873                        linked_edits
 5874                            .entry(buffer.clone())
 5875                            .or_default()
 5876                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5877                    }
 5878                }
 5879            }
 5880        }
 5881
 5882        let common_prefix_len = old_text
 5883            .chars()
 5884            .zip(new_text.chars())
 5885            .take_while(|(a, b)| a == b)
 5886            .map(|(a, _)| a.len_utf8())
 5887            .sum::<usize>();
 5888
 5889        cx.emit(EditorEvent::InputHandled {
 5890            utf16_range_to_replace: None,
 5891            text: new_text[common_prefix_len..].into(),
 5892        });
 5893
 5894        self.transact(window, cx, |editor, window, cx| {
 5895            if let Some(mut snippet) = snippet {
 5896                snippet.text = new_text.to_string();
 5897                editor
 5898                    .insert_snippet(&ranges, snippet, window, cx)
 5899                    .log_err();
 5900            } else {
 5901                editor.buffer.update(cx, |multi_buffer, cx| {
 5902                    let auto_indent = match completion.insert_text_mode {
 5903                        Some(InsertTextMode::AS_IS) => None,
 5904                        _ => editor.autoindent_mode.clone(),
 5905                    };
 5906                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5907                    multi_buffer.edit(edits, auto_indent, cx);
 5908                });
 5909            }
 5910            for (buffer, edits) in linked_edits {
 5911                buffer.update(cx, |buffer, cx| {
 5912                    let snapshot = buffer.snapshot();
 5913                    let edits = edits
 5914                        .into_iter()
 5915                        .map(|(range, text)| {
 5916                            use text::ToPoint as TP;
 5917                            let end_point = TP::to_point(&range.end, &snapshot);
 5918                            let start_point = TP::to_point(&range.start, &snapshot);
 5919                            (start_point..end_point, text)
 5920                        })
 5921                        .sorted_by_key(|(range, _)| range.start);
 5922                    buffer.edit(edits, None, cx);
 5923                })
 5924            }
 5925
 5926            editor.refresh_inline_completion(true, false, window, cx);
 5927        });
 5928        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), &snapshot);
 5929
 5930        let show_new_completions_on_confirm = completion
 5931            .confirm
 5932            .as_ref()
 5933            .map_or(false, |confirm| confirm(intent, window, cx));
 5934        if show_new_completions_on_confirm {
 5935            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5936        }
 5937
 5938        let provider = self.completion_provider.as_ref()?;
 5939        drop(completion);
 5940        let apply_edits = provider.apply_additional_edits_for_completion(
 5941            buffer_handle,
 5942            completions_menu.completions.clone(),
 5943            candidate_id,
 5944            true,
 5945            cx,
 5946        );
 5947
 5948        let editor_settings = EditorSettings::get_global(cx);
 5949        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5950            // After the code completion is finished, users often want to know what signatures are needed.
 5951            // so we should automatically call signature_help
 5952            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5953        }
 5954
 5955        Some(cx.foreground_executor().spawn(async move {
 5956            apply_edits.await?;
 5957            Ok(())
 5958        }))
 5959    }
 5960
 5961    pub fn toggle_code_actions(
 5962        &mut self,
 5963        action: &ToggleCodeActions,
 5964        window: &mut Window,
 5965        cx: &mut Context<Self>,
 5966    ) {
 5967        let quick_launch = action.quick_launch;
 5968        let mut context_menu = self.context_menu.borrow_mut();
 5969        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5970            if code_actions.deployed_from == action.deployed_from {
 5971                // Toggle if we're selecting the same one
 5972                *context_menu = None;
 5973                cx.notify();
 5974                return;
 5975            } else {
 5976                // Otherwise, clear it and start a new one
 5977                *context_menu = None;
 5978                cx.notify();
 5979            }
 5980        }
 5981        drop(context_menu);
 5982        let snapshot = self.snapshot(window, cx);
 5983        let deployed_from = action.deployed_from.clone();
 5984        let action = action.clone();
 5985        self.completion_tasks.clear();
 5986        self.discard_inline_completion(false, cx);
 5987
 5988        let multibuffer_point = match &action.deployed_from {
 5989            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5990                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5991            }
 5992            _ => self.selections.newest::<Point>(cx).head(),
 5993        };
 5994        let Some((buffer, buffer_row)) = snapshot
 5995            .buffer_snapshot
 5996            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5997            .and_then(|(buffer_snapshot, range)| {
 5998                self.buffer()
 5999                    .read(cx)
 6000                    .buffer(buffer_snapshot.remote_id())
 6001                    .map(|buffer| (buffer, range.start.row))
 6002            })
 6003        else {
 6004            return;
 6005        };
 6006        let buffer_id = buffer.read(cx).remote_id();
 6007        let tasks = self
 6008            .tasks
 6009            .get(&(buffer_id, buffer_row))
 6010            .map(|t| Arc::new(t.to_owned()));
 6011
 6012        if !self.focus_handle.is_focused(window) {
 6013            return;
 6014        }
 6015        let project = self.project.clone();
 6016
 6017        let code_actions_task = match deployed_from {
 6018            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6019            _ => self.code_actions(buffer_row, window, cx),
 6020        };
 6021
 6022        let runnable_task = match deployed_from {
 6023            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6024            _ => {
 6025                let mut task_context_task = Task::ready(None);
 6026                if let Some(tasks) = &tasks {
 6027                    if let Some(project) = project {
 6028                        task_context_task =
 6029                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 6030                    }
 6031                }
 6032
 6033                cx.spawn_in(window, {
 6034                    let buffer = buffer.clone();
 6035                    async move |editor, cx| {
 6036                        let task_context = task_context_task.await;
 6037
 6038                        let resolved_tasks =
 6039                            tasks
 6040                                .zip(task_context.clone())
 6041                                .map(|(tasks, task_context)| ResolvedTasks {
 6042                                    templates: tasks.resolve(&task_context).collect(),
 6043                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6044                                        multibuffer_point.row,
 6045                                        tasks.column,
 6046                                    )),
 6047                                });
 6048                        let debug_scenarios = editor
 6049                            .update(cx, |editor, cx| {
 6050                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6051                            })?
 6052                            .await;
 6053                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6054                    }
 6055                })
 6056            }
 6057        };
 6058
 6059        cx.spawn_in(window, async move |editor, cx| {
 6060            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6061            let code_actions = code_actions_task.await;
 6062            let spawn_straight_away = quick_launch
 6063                && resolved_tasks
 6064                    .as_ref()
 6065                    .map_or(false, |tasks| tasks.templates.len() == 1)
 6066                && code_actions
 6067                    .as_ref()
 6068                    .map_or(true, |actions| actions.is_empty())
 6069                && debug_scenarios.is_empty();
 6070
 6071            editor.update_in(cx, |editor, window, cx| {
 6072                crate::hover_popover::hide_hover(editor, cx);
 6073                let actions = CodeActionContents::new(
 6074                    resolved_tasks,
 6075                    code_actions,
 6076                    debug_scenarios,
 6077                    task_context.unwrap_or_default(),
 6078                );
 6079
 6080                // Don't show the menu if there are no actions available
 6081                if actions.is_empty() {
 6082                    cx.notify();
 6083                    return Task::ready(Ok(()));
 6084                }
 6085
 6086                *editor.context_menu.borrow_mut() =
 6087                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6088                        buffer,
 6089                        actions,
 6090                        selected_item: Default::default(),
 6091                        scroll_handle: UniformListScrollHandle::default(),
 6092                        deployed_from,
 6093                    }));
 6094                cx.notify();
 6095                if spawn_straight_away {
 6096                    if let Some(task) = editor.confirm_code_action(
 6097                        &ConfirmCodeAction { item_ix: Some(0) },
 6098                        window,
 6099                        cx,
 6100                    ) {
 6101                        return task;
 6102                    }
 6103                }
 6104
 6105                Task::ready(Ok(()))
 6106            })
 6107        })
 6108        .detach_and_log_err(cx);
 6109    }
 6110
 6111    fn debug_scenarios(
 6112        &mut self,
 6113        resolved_tasks: &Option<ResolvedTasks>,
 6114        buffer: &Entity<Buffer>,
 6115        cx: &mut App,
 6116    ) -> Task<Vec<task::DebugScenario>> {
 6117        maybe!({
 6118            let project = self.project.as_ref()?;
 6119            let dap_store = project.read(cx).dap_store();
 6120            let mut scenarios = vec![];
 6121            let resolved_tasks = resolved_tasks.as_ref()?;
 6122            let buffer = buffer.read(cx);
 6123            let language = buffer.language()?;
 6124            let file = buffer.file();
 6125            let debug_adapter = language_settings(language.name().into(), file, cx)
 6126                .debuggers
 6127                .first()
 6128                .map(SharedString::from)
 6129                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6130
 6131            dap_store.update(cx, |dap_store, cx| {
 6132                for (_, task) in &resolved_tasks.templates {
 6133                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6134                        task.original_task().clone(),
 6135                        debug_adapter.clone().into(),
 6136                        task.display_label().to_owned().into(),
 6137                        cx,
 6138                    );
 6139                    scenarios.push(maybe_scenario);
 6140                }
 6141            });
 6142            Some(cx.background_spawn(async move {
 6143                let scenarios = futures::future::join_all(scenarios)
 6144                    .await
 6145                    .into_iter()
 6146                    .flatten()
 6147                    .collect::<Vec<_>>();
 6148                scenarios
 6149            }))
 6150        })
 6151        .unwrap_or_else(|| Task::ready(vec![]))
 6152    }
 6153
 6154    fn code_actions(
 6155        &mut self,
 6156        buffer_row: u32,
 6157        window: &mut Window,
 6158        cx: &mut Context<Self>,
 6159    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6160        let mut task = self.code_actions_task.take();
 6161        cx.spawn_in(window, async move |editor, cx| {
 6162            while let Some(prev_task) = task {
 6163                prev_task.await.log_err();
 6164                task = editor
 6165                    .update(cx, |this, _| this.code_actions_task.take())
 6166                    .ok()?;
 6167            }
 6168
 6169            editor
 6170                .update(cx, |editor, cx| {
 6171                    editor
 6172                        .available_code_actions
 6173                        .clone()
 6174                        .and_then(|(location, code_actions)| {
 6175                            let snapshot = location.buffer.read(cx).snapshot();
 6176                            let point_range = location.range.to_point(&snapshot);
 6177                            let point_range = point_range.start.row..=point_range.end.row;
 6178                            if point_range.contains(&buffer_row) {
 6179                                Some(code_actions)
 6180                            } else {
 6181                                None
 6182                            }
 6183                        })
 6184                })
 6185                .ok()
 6186                .flatten()
 6187        })
 6188    }
 6189
 6190    pub fn confirm_code_action(
 6191        &mut self,
 6192        action: &ConfirmCodeAction,
 6193        window: &mut Window,
 6194        cx: &mut Context<Self>,
 6195    ) -> Option<Task<Result<()>>> {
 6196        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6197
 6198        let actions_menu =
 6199            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6200                menu
 6201            } else {
 6202                return None;
 6203            };
 6204
 6205        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6206        let action = actions_menu.actions.get(action_ix)?;
 6207        let title = action.label();
 6208        let buffer = actions_menu.buffer;
 6209        let workspace = self.workspace()?;
 6210
 6211        match action {
 6212            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6213                workspace.update(cx, |workspace, cx| {
 6214                    workspace.schedule_resolved_task(
 6215                        task_source_kind,
 6216                        resolved_task,
 6217                        false,
 6218                        window,
 6219                        cx,
 6220                    );
 6221
 6222                    Some(Task::ready(Ok(())))
 6223                })
 6224            }
 6225            CodeActionsItem::CodeAction {
 6226                excerpt_id,
 6227                action,
 6228                provider,
 6229            } => {
 6230                let apply_code_action =
 6231                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6232                let workspace = workspace.downgrade();
 6233                Some(cx.spawn_in(window, async move |editor, cx| {
 6234                    let project_transaction = apply_code_action.await?;
 6235                    Self::open_project_transaction(
 6236                        &editor,
 6237                        workspace,
 6238                        project_transaction,
 6239                        title,
 6240                        cx,
 6241                    )
 6242                    .await
 6243                }))
 6244            }
 6245            CodeActionsItem::DebugScenario(scenario) => {
 6246                let context = actions_menu.actions.context.clone();
 6247
 6248                workspace.update(cx, |workspace, cx| {
 6249                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6250                    workspace.start_debug_session(
 6251                        scenario,
 6252                        context,
 6253                        Some(buffer),
 6254                        None,
 6255                        window,
 6256                        cx,
 6257                    );
 6258                });
 6259                Some(Task::ready(Ok(())))
 6260            }
 6261        }
 6262    }
 6263
 6264    pub async fn open_project_transaction(
 6265        this: &WeakEntity<Editor>,
 6266        workspace: WeakEntity<Workspace>,
 6267        transaction: ProjectTransaction,
 6268        title: String,
 6269        cx: &mut AsyncWindowContext,
 6270    ) -> Result<()> {
 6271        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6272        cx.update(|_, cx| {
 6273            entries.sort_unstable_by_key(|(buffer, _)| {
 6274                buffer.read(cx).file().map(|f| f.path().clone())
 6275            });
 6276        })?;
 6277
 6278        // If the project transaction's edits are all contained within this editor, then
 6279        // avoid opening a new editor to display them.
 6280
 6281        if let Some((buffer, transaction)) = entries.first() {
 6282            if entries.len() == 1 {
 6283                let excerpt = this.update(cx, |editor, cx| {
 6284                    editor
 6285                        .buffer()
 6286                        .read(cx)
 6287                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6288                })?;
 6289                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6290                    if excerpted_buffer == *buffer {
 6291                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6292                            let excerpt_range = excerpt_range.to_offset(buffer);
 6293                            buffer
 6294                                .edited_ranges_for_transaction::<usize>(transaction)
 6295                                .all(|range| {
 6296                                    excerpt_range.start <= range.start
 6297                                        && excerpt_range.end >= range.end
 6298                                })
 6299                        })?;
 6300
 6301                        if all_edits_within_excerpt {
 6302                            return Ok(());
 6303                        }
 6304                    }
 6305                }
 6306            }
 6307        } else {
 6308            return Ok(());
 6309        }
 6310
 6311        let mut ranges_to_highlight = Vec::new();
 6312        let excerpt_buffer = cx.new(|cx| {
 6313            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6314            for (buffer_handle, transaction) in &entries {
 6315                let edited_ranges = buffer_handle
 6316                    .read(cx)
 6317                    .edited_ranges_for_transaction::<Point>(transaction)
 6318                    .collect::<Vec<_>>();
 6319                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6320                    PathKey::for_buffer(buffer_handle, cx),
 6321                    buffer_handle.clone(),
 6322                    edited_ranges,
 6323                    DEFAULT_MULTIBUFFER_CONTEXT,
 6324                    cx,
 6325                );
 6326
 6327                ranges_to_highlight.extend(ranges);
 6328            }
 6329            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6330            multibuffer
 6331        })?;
 6332
 6333        workspace.update_in(cx, |workspace, window, cx| {
 6334            let project = workspace.project().clone();
 6335            let editor =
 6336                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6337            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6338            editor.update(cx, |editor, cx| {
 6339                editor.highlight_background::<Self>(
 6340                    &ranges_to_highlight,
 6341                    |theme| theme.colors().editor_highlighted_line_background,
 6342                    cx,
 6343                );
 6344            });
 6345        })?;
 6346
 6347        Ok(())
 6348    }
 6349
 6350    pub fn clear_code_action_providers(&mut self) {
 6351        self.code_action_providers.clear();
 6352        self.available_code_actions.take();
 6353    }
 6354
 6355    pub fn add_code_action_provider(
 6356        &mut self,
 6357        provider: Rc<dyn CodeActionProvider>,
 6358        window: &mut Window,
 6359        cx: &mut Context<Self>,
 6360    ) {
 6361        if self
 6362            .code_action_providers
 6363            .iter()
 6364            .any(|existing_provider| existing_provider.id() == provider.id())
 6365        {
 6366            return;
 6367        }
 6368
 6369        self.code_action_providers.push(provider);
 6370        self.refresh_code_actions(window, cx);
 6371    }
 6372
 6373    pub fn remove_code_action_provider(
 6374        &mut self,
 6375        id: Arc<str>,
 6376        window: &mut Window,
 6377        cx: &mut Context<Self>,
 6378    ) {
 6379        self.code_action_providers
 6380            .retain(|provider| provider.id() != id);
 6381        self.refresh_code_actions(window, cx);
 6382    }
 6383
 6384    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6385        !self.code_action_providers.is_empty()
 6386            && EditorSettings::get_global(cx).toolbar.code_actions
 6387    }
 6388
 6389    pub fn has_available_code_actions(&self) -> bool {
 6390        self.available_code_actions
 6391            .as_ref()
 6392            .is_some_and(|(_, actions)| !actions.is_empty())
 6393    }
 6394
 6395    fn render_inline_code_actions(
 6396        &self,
 6397        icon_size: ui::IconSize,
 6398        display_row: DisplayRow,
 6399        is_active: bool,
 6400        cx: &mut Context<Self>,
 6401    ) -> AnyElement {
 6402        let show_tooltip = !self.context_menu_visible();
 6403        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6404            .icon_size(icon_size)
 6405            .shape(ui::IconButtonShape::Square)
 6406            .style(ButtonStyle::Transparent)
 6407            .icon_color(ui::Color::Hidden)
 6408            .toggle_state(is_active)
 6409            .when(show_tooltip, |this| {
 6410                this.tooltip({
 6411                    let focus_handle = self.focus_handle.clone();
 6412                    move |window, cx| {
 6413                        Tooltip::for_action_in(
 6414                            "Toggle Code Actions",
 6415                            &ToggleCodeActions {
 6416                                deployed_from: None,
 6417                                quick_launch: false,
 6418                            },
 6419                            &focus_handle,
 6420                            window,
 6421                            cx,
 6422                        )
 6423                    }
 6424                })
 6425            })
 6426            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6427                window.focus(&editor.focus_handle(cx));
 6428                editor.toggle_code_actions(
 6429                    &crate::actions::ToggleCodeActions {
 6430                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6431                            display_row,
 6432                        )),
 6433                        quick_launch: false,
 6434                    },
 6435                    window,
 6436                    cx,
 6437                );
 6438            }))
 6439            .into_any_element()
 6440    }
 6441
 6442    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6443        &self.context_menu
 6444    }
 6445
 6446    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6447        let newest_selection = self.selections.newest_anchor().clone();
 6448        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6449        let buffer = self.buffer.read(cx);
 6450        if newest_selection.head().diff_base_anchor.is_some() {
 6451            return None;
 6452        }
 6453        let (start_buffer, start) =
 6454            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6455        let (end_buffer, end) =
 6456            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6457        if start_buffer != end_buffer {
 6458            return None;
 6459        }
 6460
 6461        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6462            cx.background_executor()
 6463                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6464                .await;
 6465
 6466            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6467                let providers = this.code_action_providers.clone();
 6468                let tasks = this
 6469                    .code_action_providers
 6470                    .iter()
 6471                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6472                    .collect::<Vec<_>>();
 6473                (providers, tasks)
 6474            })?;
 6475
 6476            let mut actions = Vec::new();
 6477            for (provider, provider_actions) in
 6478                providers.into_iter().zip(future::join_all(tasks).await)
 6479            {
 6480                if let Some(provider_actions) = provider_actions.log_err() {
 6481                    actions.extend(provider_actions.into_iter().map(|action| {
 6482                        AvailableCodeAction {
 6483                            excerpt_id: newest_selection.start.excerpt_id,
 6484                            action,
 6485                            provider: provider.clone(),
 6486                        }
 6487                    }));
 6488                }
 6489            }
 6490
 6491            this.update(cx, |this, cx| {
 6492                this.available_code_actions = if actions.is_empty() {
 6493                    None
 6494                } else {
 6495                    Some((
 6496                        Location {
 6497                            buffer: start_buffer,
 6498                            range: start..end,
 6499                        },
 6500                        actions.into(),
 6501                    ))
 6502                };
 6503                cx.notify();
 6504            })
 6505        }));
 6506        None
 6507    }
 6508
 6509    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6510        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6511            self.show_git_blame_inline = false;
 6512
 6513            self.show_git_blame_inline_delay_task =
 6514                Some(cx.spawn_in(window, async move |this, cx| {
 6515                    cx.background_executor().timer(delay).await;
 6516
 6517                    this.update(cx, |this, cx| {
 6518                        this.show_git_blame_inline = true;
 6519                        cx.notify();
 6520                    })
 6521                    .log_err();
 6522                }));
 6523        }
 6524    }
 6525
 6526    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6527        let snapshot = self.snapshot(window, cx);
 6528        let cursor = self.selections.newest::<Point>(cx).head();
 6529        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6530        else {
 6531            return;
 6532        };
 6533
 6534        let Some(blame) = self.blame.as_ref() else {
 6535            return;
 6536        };
 6537
 6538        let row_info = RowInfo {
 6539            buffer_id: Some(buffer.remote_id()),
 6540            buffer_row: Some(point.row),
 6541            ..Default::default()
 6542        };
 6543        let Some(blame_entry) = blame
 6544            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6545            .flatten()
 6546        else {
 6547            return;
 6548        };
 6549
 6550        let anchor = self.selections.newest_anchor().head();
 6551        let position = self.to_pixel_point(anchor, &snapshot, window);
 6552        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6553            self.show_blame_popover(&blame_entry, position + last_bounds.origin, true, cx);
 6554        };
 6555    }
 6556
 6557    fn show_blame_popover(
 6558        &mut self,
 6559        blame_entry: &BlameEntry,
 6560        position: gpui::Point<Pixels>,
 6561        ignore_timeout: bool,
 6562        cx: &mut Context<Self>,
 6563    ) {
 6564        if let Some(state) = &mut self.inline_blame_popover {
 6565            state.hide_task.take();
 6566        } else {
 6567            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6568            let blame_entry = blame_entry.clone();
 6569            let show_task = cx.spawn(async move |editor, cx| {
 6570                if !ignore_timeout {
 6571                    cx.background_executor()
 6572                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6573                        .await;
 6574                }
 6575                editor
 6576                    .update(cx, |editor, cx| {
 6577                        editor.inline_blame_popover_show_task.take();
 6578                        let Some(blame) = editor.blame.as_ref() else {
 6579                            return;
 6580                        };
 6581                        let blame = blame.read(cx);
 6582                        let details = blame.details_for_entry(&blame_entry);
 6583                        let markdown = cx.new(|cx| {
 6584                            Markdown::new(
 6585                                details
 6586                                    .as_ref()
 6587                                    .map(|message| message.message.clone())
 6588                                    .unwrap_or_default(),
 6589                                None,
 6590                                None,
 6591                                cx,
 6592                            )
 6593                        });
 6594                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6595                            position,
 6596                            hide_task: None,
 6597                            popover_bounds: None,
 6598                            popover_state: InlineBlamePopoverState {
 6599                                scroll_handle: ScrollHandle::new(),
 6600                                commit_message: details,
 6601                                markdown,
 6602                            },
 6603                            keyboard_grace: ignore_timeout,
 6604                        });
 6605                        cx.notify();
 6606                    })
 6607                    .ok();
 6608            });
 6609            self.inline_blame_popover_show_task = Some(show_task);
 6610        }
 6611    }
 6612
 6613    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6614        self.inline_blame_popover_show_task.take();
 6615        if let Some(state) = &mut self.inline_blame_popover {
 6616            let hide_task = cx.spawn(async move |editor, cx| {
 6617                cx.background_executor()
 6618                    .timer(std::time::Duration::from_millis(100))
 6619                    .await;
 6620                editor
 6621                    .update(cx, |editor, cx| {
 6622                        editor.inline_blame_popover.take();
 6623                        cx.notify();
 6624                    })
 6625                    .ok();
 6626            });
 6627            state.hide_task = Some(hide_task);
 6628        }
 6629    }
 6630
 6631    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6632        if self.pending_rename.is_some() {
 6633            return None;
 6634        }
 6635
 6636        let provider = self.semantics_provider.clone()?;
 6637        let buffer = self.buffer.read(cx);
 6638        let newest_selection = self.selections.newest_anchor().clone();
 6639        let cursor_position = newest_selection.head();
 6640        let (cursor_buffer, cursor_buffer_position) =
 6641            buffer.text_anchor_for_position(cursor_position, cx)?;
 6642        let (tail_buffer, tail_buffer_position) =
 6643            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6644        if cursor_buffer != tail_buffer {
 6645            return None;
 6646        }
 6647
 6648        let snapshot = cursor_buffer.read(cx).snapshot();
 6649        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6650        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6651        if start_word_range != end_word_range {
 6652            self.document_highlights_task.take();
 6653            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6654            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6655            return None;
 6656        }
 6657
 6658        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6659        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6660            cx.background_executor()
 6661                .timer(Duration::from_millis(debounce))
 6662                .await;
 6663
 6664            let highlights = if let Some(highlights) = cx
 6665                .update(|cx| {
 6666                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6667                })
 6668                .ok()
 6669                .flatten()
 6670            {
 6671                highlights.await.log_err()
 6672            } else {
 6673                None
 6674            };
 6675
 6676            if let Some(highlights) = highlights {
 6677                this.update(cx, |this, cx| {
 6678                    if this.pending_rename.is_some() {
 6679                        return;
 6680                    }
 6681
 6682                    let buffer_id = cursor_position.buffer_id;
 6683                    let buffer = this.buffer.read(cx);
 6684                    if !buffer
 6685                        .text_anchor_for_position(cursor_position, cx)
 6686                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6687                    {
 6688                        return;
 6689                    }
 6690
 6691                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6692                    let mut write_ranges = Vec::new();
 6693                    let mut read_ranges = Vec::new();
 6694                    for highlight in highlights {
 6695                        for (excerpt_id, excerpt_range) in
 6696                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6697                        {
 6698                            let start = highlight
 6699                                .range
 6700                                .start
 6701                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6702                            let end = highlight
 6703                                .range
 6704                                .end
 6705                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6706                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6707                                continue;
 6708                            }
 6709
 6710                            let range = Anchor {
 6711                                buffer_id,
 6712                                excerpt_id,
 6713                                text_anchor: start,
 6714                                diff_base_anchor: None,
 6715                            }..Anchor {
 6716                                buffer_id,
 6717                                excerpt_id,
 6718                                text_anchor: end,
 6719                                diff_base_anchor: None,
 6720                            };
 6721                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6722                                write_ranges.push(range);
 6723                            } else {
 6724                                read_ranges.push(range);
 6725                            }
 6726                        }
 6727                    }
 6728
 6729                    this.highlight_background::<DocumentHighlightRead>(
 6730                        &read_ranges,
 6731                        |theme| theme.colors().editor_document_highlight_read_background,
 6732                        cx,
 6733                    );
 6734                    this.highlight_background::<DocumentHighlightWrite>(
 6735                        &write_ranges,
 6736                        |theme| theme.colors().editor_document_highlight_write_background,
 6737                        cx,
 6738                    );
 6739                    cx.notify();
 6740                })
 6741                .log_err();
 6742            }
 6743        }));
 6744        None
 6745    }
 6746
 6747    fn prepare_highlight_query_from_selection(
 6748        &mut self,
 6749        cx: &mut Context<Editor>,
 6750    ) -> Option<(String, Range<Anchor>)> {
 6751        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6752            return None;
 6753        }
 6754        if !EditorSettings::get_global(cx).selection_highlight {
 6755            return None;
 6756        }
 6757        if self.selections.count() != 1 || self.selections.line_mode {
 6758            return None;
 6759        }
 6760        let selection = self.selections.newest::<Point>(cx);
 6761        if selection.is_empty() || selection.start.row != selection.end.row {
 6762            return None;
 6763        }
 6764        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6765        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6766        let query = multi_buffer_snapshot
 6767            .text_for_range(selection_anchor_range.clone())
 6768            .collect::<String>();
 6769        if query.trim().is_empty() {
 6770            return None;
 6771        }
 6772        Some((query, selection_anchor_range))
 6773    }
 6774
 6775    fn update_selection_occurrence_highlights(
 6776        &mut self,
 6777        query_text: String,
 6778        query_range: Range<Anchor>,
 6779        multi_buffer_range_to_query: Range<Point>,
 6780        use_debounce: bool,
 6781        window: &mut Window,
 6782        cx: &mut Context<Editor>,
 6783    ) -> Task<()> {
 6784        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6785        cx.spawn_in(window, async move |editor, cx| {
 6786            if use_debounce {
 6787                cx.background_executor()
 6788                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6789                    .await;
 6790            }
 6791            let match_task = cx.background_spawn(async move {
 6792                let buffer_ranges = multi_buffer_snapshot
 6793                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6794                    .into_iter()
 6795                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6796                let mut match_ranges = Vec::new();
 6797                let Ok(regex) = project::search::SearchQuery::text(
 6798                    query_text.clone(),
 6799                    false,
 6800                    false,
 6801                    false,
 6802                    Default::default(),
 6803                    Default::default(),
 6804                    false,
 6805                    None,
 6806                ) else {
 6807                    return Vec::default();
 6808                };
 6809                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6810                    match_ranges.extend(
 6811                        regex
 6812                            .search(&buffer_snapshot, Some(search_range.clone()))
 6813                            .await
 6814                            .into_iter()
 6815                            .filter_map(|match_range| {
 6816                                let match_start = buffer_snapshot
 6817                                    .anchor_after(search_range.start + match_range.start);
 6818                                let match_end = buffer_snapshot
 6819                                    .anchor_before(search_range.start + match_range.end);
 6820                                let match_anchor_range = Anchor::range_in_buffer(
 6821                                    excerpt_id,
 6822                                    buffer_snapshot.remote_id(),
 6823                                    match_start..match_end,
 6824                                );
 6825                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6826                            }),
 6827                    );
 6828                }
 6829                match_ranges
 6830            });
 6831            let match_ranges = match_task.await;
 6832            editor
 6833                .update_in(cx, |editor, _, cx| {
 6834                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6835                    if !match_ranges.is_empty() {
 6836                        editor.highlight_background::<SelectedTextHighlight>(
 6837                            &match_ranges,
 6838                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6839                            cx,
 6840                        )
 6841                    }
 6842                })
 6843                .log_err();
 6844        })
 6845    }
 6846
 6847    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6848        struct NewlineFold;
 6849        let type_id = std::any::TypeId::of::<NewlineFold>();
 6850        if !self.mode.is_single_line() {
 6851            return;
 6852        }
 6853        let snapshot = self.snapshot(window, cx);
 6854        if snapshot.buffer_snapshot.max_point().row == 0 {
 6855            return;
 6856        }
 6857        let task = cx.background_spawn(async move {
 6858            let new_newlines = snapshot
 6859                .buffer_chars_at(0)
 6860                .filter_map(|(c, i)| {
 6861                    if c == '\n' {
 6862                        Some(
 6863                            snapshot.buffer_snapshot.anchor_after(i)
 6864                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6865                        )
 6866                    } else {
 6867                        None
 6868                    }
 6869                })
 6870                .collect::<Vec<_>>();
 6871            let existing_newlines = snapshot
 6872                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6873                .filter_map(|fold| {
 6874                    if fold.placeholder.type_tag == Some(type_id) {
 6875                        Some(fold.range.start..fold.range.end)
 6876                    } else {
 6877                        None
 6878                    }
 6879                })
 6880                .collect::<Vec<_>>();
 6881
 6882            (new_newlines, existing_newlines)
 6883        });
 6884        self.folding_newlines = cx.spawn(async move |this, cx| {
 6885            let (new_newlines, existing_newlines) = task.await;
 6886            if new_newlines == existing_newlines {
 6887                return;
 6888            }
 6889            let placeholder = FoldPlaceholder {
 6890                render: Arc::new(move |_, _, cx| {
 6891                    div()
 6892                        .bg(cx.theme().status().hint_background)
 6893                        .border_b_1()
 6894                        .size_full()
 6895                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6896                        .border_color(cx.theme().status().hint)
 6897                        .child("\\n")
 6898                        .into_any()
 6899                }),
 6900                constrain_width: false,
 6901                merge_adjacent: false,
 6902                type_tag: Some(type_id),
 6903            };
 6904            let creases = new_newlines
 6905                .into_iter()
 6906                .map(|range| Crease::simple(range, placeholder.clone()))
 6907                .collect();
 6908            this.update(cx, |this, cx| {
 6909                this.display_map.update(cx, |display_map, cx| {
 6910                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6911                    display_map.fold(creases, cx);
 6912                });
 6913            })
 6914            .ok();
 6915        });
 6916    }
 6917
 6918    fn refresh_selected_text_highlights(
 6919        &mut self,
 6920        on_buffer_edit: bool,
 6921        window: &mut Window,
 6922        cx: &mut Context<Editor>,
 6923    ) {
 6924        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6925        else {
 6926            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6927            self.quick_selection_highlight_task.take();
 6928            self.debounced_selection_highlight_task.take();
 6929            return;
 6930        };
 6931        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6932        if on_buffer_edit
 6933            || self
 6934                .quick_selection_highlight_task
 6935                .as_ref()
 6936                .map_or(true, |(prev_anchor_range, _)| {
 6937                    prev_anchor_range != &query_range
 6938                })
 6939        {
 6940            let multi_buffer_visible_start = self
 6941                .scroll_manager
 6942                .anchor()
 6943                .anchor
 6944                .to_point(&multi_buffer_snapshot);
 6945            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6946                multi_buffer_visible_start
 6947                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6948                Bias::Left,
 6949            );
 6950            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6951            self.quick_selection_highlight_task = Some((
 6952                query_range.clone(),
 6953                self.update_selection_occurrence_highlights(
 6954                    query_text.clone(),
 6955                    query_range.clone(),
 6956                    multi_buffer_visible_range,
 6957                    false,
 6958                    window,
 6959                    cx,
 6960                ),
 6961            ));
 6962        }
 6963        if on_buffer_edit
 6964            || self
 6965                .debounced_selection_highlight_task
 6966                .as_ref()
 6967                .map_or(true, |(prev_anchor_range, _)| {
 6968                    prev_anchor_range != &query_range
 6969                })
 6970        {
 6971            let multi_buffer_start = multi_buffer_snapshot
 6972                .anchor_before(0)
 6973                .to_point(&multi_buffer_snapshot);
 6974            let multi_buffer_end = multi_buffer_snapshot
 6975                .anchor_after(multi_buffer_snapshot.len())
 6976                .to_point(&multi_buffer_snapshot);
 6977            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6978            self.debounced_selection_highlight_task = Some((
 6979                query_range.clone(),
 6980                self.update_selection_occurrence_highlights(
 6981                    query_text,
 6982                    query_range,
 6983                    multi_buffer_full_range,
 6984                    true,
 6985                    window,
 6986                    cx,
 6987                ),
 6988            ));
 6989        }
 6990    }
 6991
 6992    pub fn refresh_inline_completion(
 6993        &mut self,
 6994        debounce: bool,
 6995        user_requested: bool,
 6996        window: &mut Window,
 6997        cx: &mut Context<Self>,
 6998    ) -> Option<()> {
 6999        let provider = self.edit_prediction_provider()?;
 7000        let cursor = self.selections.newest_anchor().head();
 7001        let (buffer, cursor_buffer_position) =
 7002            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7003
 7004        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7005            self.discard_inline_completion(false, cx);
 7006            return None;
 7007        }
 7008
 7009        if !user_requested
 7010            && (!self.should_show_edit_predictions()
 7011                || !self.is_focused(window)
 7012                || buffer.read(cx).is_empty())
 7013        {
 7014            self.discard_inline_completion(false, cx);
 7015            return None;
 7016        }
 7017
 7018        self.update_visible_inline_completion(window, cx);
 7019        provider.refresh(
 7020            self.project.clone(),
 7021            buffer,
 7022            cursor_buffer_position,
 7023            debounce,
 7024            cx,
 7025        );
 7026        Some(())
 7027    }
 7028
 7029    fn show_edit_predictions_in_menu(&self) -> bool {
 7030        match self.edit_prediction_settings {
 7031            EditPredictionSettings::Disabled => false,
 7032            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7033        }
 7034    }
 7035
 7036    pub fn edit_predictions_enabled(&self) -> bool {
 7037        match self.edit_prediction_settings {
 7038            EditPredictionSettings::Disabled => false,
 7039            EditPredictionSettings::Enabled { .. } => true,
 7040        }
 7041    }
 7042
 7043    fn edit_prediction_requires_modifier(&self) -> bool {
 7044        match self.edit_prediction_settings {
 7045            EditPredictionSettings::Disabled => false,
 7046            EditPredictionSettings::Enabled {
 7047                preview_requires_modifier,
 7048                ..
 7049            } => preview_requires_modifier,
 7050        }
 7051    }
 7052
 7053    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7054        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7055            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7056        } else {
 7057            let selection = self.selections.newest_anchor();
 7058            let cursor = selection.head();
 7059
 7060            if let Some((buffer, cursor_buffer_position)) =
 7061                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7062            {
 7063                self.edit_prediction_settings =
 7064                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7065            }
 7066        }
 7067    }
 7068
 7069    fn edit_prediction_settings_at_position(
 7070        &self,
 7071        buffer: &Entity<Buffer>,
 7072        buffer_position: language::Anchor,
 7073        cx: &App,
 7074    ) -> EditPredictionSettings {
 7075        if !self.mode.is_full()
 7076            || !self.show_inline_completions_override.unwrap_or(true)
 7077            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 7078        {
 7079            return EditPredictionSettings::Disabled;
 7080        }
 7081
 7082        let buffer = buffer.read(cx);
 7083
 7084        let file = buffer.file();
 7085
 7086        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7087            return EditPredictionSettings::Disabled;
 7088        };
 7089
 7090        let by_provider = matches!(
 7091            self.menu_inline_completions_policy,
 7092            MenuInlineCompletionsPolicy::ByProvider
 7093        );
 7094
 7095        let show_in_menu = by_provider
 7096            && self
 7097                .edit_prediction_provider
 7098                .as_ref()
 7099                .map_or(false, |provider| {
 7100                    provider.provider.show_completions_in_menu()
 7101                });
 7102
 7103        let preview_requires_modifier =
 7104            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7105
 7106        EditPredictionSettings::Enabled {
 7107            show_in_menu,
 7108            preview_requires_modifier,
 7109        }
 7110    }
 7111
 7112    fn should_show_edit_predictions(&self) -> bool {
 7113        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7114    }
 7115
 7116    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7117        matches!(
 7118            self.edit_prediction_preview,
 7119            EditPredictionPreview::Active { .. }
 7120        )
 7121    }
 7122
 7123    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7124        let cursor = self.selections.newest_anchor().head();
 7125        if let Some((buffer, cursor_position)) =
 7126            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7127        {
 7128            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7129        } else {
 7130            false
 7131        }
 7132    }
 7133
 7134    pub fn supports_minimap(&self, cx: &App) -> bool {
 7135        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7136    }
 7137
 7138    fn edit_predictions_enabled_in_buffer(
 7139        &self,
 7140        buffer: &Entity<Buffer>,
 7141        buffer_position: language::Anchor,
 7142        cx: &App,
 7143    ) -> bool {
 7144        maybe!({
 7145            if self.read_only(cx) {
 7146                return Some(false);
 7147            }
 7148            let provider = self.edit_prediction_provider()?;
 7149            if !provider.is_enabled(&buffer, buffer_position, cx) {
 7150                return Some(false);
 7151            }
 7152            let buffer = buffer.read(cx);
 7153            let Some(file) = buffer.file() else {
 7154                return Some(true);
 7155            };
 7156            let settings = all_language_settings(Some(file), cx);
 7157            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7158        })
 7159        .unwrap_or(false)
 7160    }
 7161
 7162    fn cycle_inline_completion(
 7163        &mut self,
 7164        direction: Direction,
 7165        window: &mut Window,
 7166        cx: &mut Context<Self>,
 7167    ) -> Option<()> {
 7168        let provider = self.edit_prediction_provider()?;
 7169        let cursor = self.selections.newest_anchor().head();
 7170        let (buffer, cursor_buffer_position) =
 7171            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7172        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7173            return None;
 7174        }
 7175
 7176        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7177        self.update_visible_inline_completion(window, cx);
 7178
 7179        Some(())
 7180    }
 7181
 7182    pub fn show_inline_completion(
 7183        &mut self,
 7184        _: &ShowEditPrediction,
 7185        window: &mut Window,
 7186        cx: &mut Context<Self>,
 7187    ) {
 7188        if !self.has_active_inline_completion() {
 7189            self.refresh_inline_completion(false, true, window, cx);
 7190            return;
 7191        }
 7192
 7193        self.update_visible_inline_completion(window, cx);
 7194    }
 7195
 7196    pub fn display_cursor_names(
 7197        &mut self,
 7198        _: &DisplayCursorNames,
 7199        window: &mut Window,
 7200        cx: &mut Context<Self>,
 7201    ) {
 7202        self.show_cursor_names(window, cx);
 7203    }
 7204
 7205    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7206        self.show_cursor_names = true;
 7207        cx.notify();
 7208        cx.spawn_in(window, async move |this, cx| {
 7209            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7210            this.update(cx, |this, cx| {
 7211                this.show_cursor_names = false;
 7212                cx.notify()
 7213            })
 7214            .ok()
 7215        })
 7216        .detach();
 7217    }
 7218
 7219    pub fn next_edit_prediction(
 7220        &mut self,
 7221        _: &NextEditPrediction,
 7222        window: &mut Window,
 7223        cx: &mut Context<Self>,
 7224    ) {
 7225        if self.has_active_inline_completion() {
 7226            self.cycle_inline_completion(Direction::Next, window, cx);
 7227        } else {
 7228            let is_copilot_disabled = self
 7229                .refresh_inline_completion(false, true, window, cx)
 7230                .is_none();
 7231            if is_copilot_disabled {
 7232                cx.propagate();
 7233            }
 7234        }
 7235    }
 7236
 7237    pub fn previous_edit_prediction(
 7238        &mut self,
 7239        _: &PreviousEditPrediction,
 7240        window: &mut Window,
 7241        cx: &mut Context<Self>,
 7242    ) {
 7243        if self.has_active_inline_completion() {
 7244            self.cycle_inline_completion(Direction::Prev, window, cx);
 7245        } else {
 7246            let is_copilot_disabled = self
 7247                .refresh_inline_completion(false, true, window, cx)
 7248                .is_none();
 7249            if is_copilot_disabled {
 7250                cx.propagate();
 7251            }
 7252        }
 7253    }
 7254
 7255    pub fn accept_edit_prediction(
 7256        &mut self,
 7257        _: &AcceptEditPrediction,
 7258        window: &mut Window,
 7259        cx: &mut Context<Self>,
 7260    ) {
 7261        if self.show_edit_predictions_in_menu() {
 7262            self.hide_context_menu(window, cx);
 7263        }
 7264
 7265        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7266            return;
 7267        };
 7268
 7269        self.report_inline_completion_event(
 7270            active_inline_completion.completion_id.clone(),
 7271            true,
 7272            cx,
 7273        );
 7274
 7275        match &active_inline_completion.completion {
 7276            InlineCompletion::Move { target, .. } => {
 7277                let target = *target;
 7278
 7279                if let Some(position_map) = &self.last_position_map {
 7280                    if position_map
 7281                        .visible_row_range
 7282                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7283                        || !self.edit_prediction_requires_modifier()
 7284                    {
 7285                        self.unfold_ranges(&[target..target], true, false, cx);
 7286                        // Note that this is also done in vim's handler of the Tab action.
 7287                        self.change_selections(
 7288                            SelectionEffects::scroll(Autoscroll::newest()),
 7289                            window,
 7290                            cx,
 7291                            |selections| {
 7292                                selections.select_anchor_ranges([target..target]);
 7293                            },
 7294                        );
 7295                        self.clear_row_highlights::<EditPredictionPreview>();
 7296
 7297                        self.edit_prediction_preview
 7298                            .set_previous_scroll_position(None);
 7299                    } else {
 7300                        self.edit_prediction_preview
 7301                            .set_previous_scroll_position(Some(
 7302                                position_map.snapshot.scroll_anchor,
 7303                            ));
 7304
 7305                        self.highlight_rows::<EditPredictionPreview>(
 7306                            target..target,
 7307                            cx.theme().colors().editor_highlighted_line_background,
 7308                            RowHighlightOptions {
 7309                                autoscroll: true,
 7310                                ..Default::default()
 7311                            },
 7312                            cx,
 7313                        );
 7314                        self.request_autoscroll(Autoscroll::fit(), cx);
 7315                    }
 7316                }
 7317            }
 7318            InlineCompletion::Edit { edits, .. } => {
 7319                if let Some(provider) = self.edit_prediction_provider() {
 7320                    provider.accept(cx);
 7321                }
 7322
 7323                // Store the transaction ID and selections before applying the edit
 7324                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7325
 7326                let snapshot = self.buffer.read(cx).snapshot(cx);
 7327                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7328
 7329                self.buffer.update(cx, |buffer, cx| {
 7330                    buffer.edit(edits.iter().cloned(), None, cx)
 7331                });
 7332
 7333                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7334                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7335                });
 7336
 7337                let selections = self.selections.disjoint_anchors();
 7338                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7339                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7340                    if has_new_transaction {
 7341                        self.selection_history
 7342                            .insert_transaction(transaction_id_now, selections);
 7343                    }
 7344                }
 7345
 7346                self.update_visible_inline_completion(window, cx);
 7347                if self.active_inline_completion.is_none() {
 7348                    self.refresh_inline_completion(true, true, window, cx);
 7349                }
 7350
 7351                cx.notify();
 7352            }
 7353        }
 7354
 7355        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7356    }
 7357
 7358    pub fn accept_partial_inline_completion(
 7359        &mut self,
 7360        _: &AcceptPartialEditPrediction,
 7361        window: &mut Window,
 7362        cx: &mut Context<Self>,
 7363    ) {
 7364        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7365            return;
 7366        };
 7367        if self.selections.count() != 1 {
 7368            return;
 7369        }
 7370
 7371        self.report_inline_completion_event(
 7372            active_inline_completion.completion_id.clone(),
 7373            true,
 7374            cx,
 7375        );
 7376
 7377        match &active_inline_completion.completion {
 7378            InlineCompletion::Move { target, .. } => {
 7379                let target = *target;
 7380                self.change_selections(
 7381                    SelectionEffects::scroll(Autoscroll::newest()),
 7382                    window,
 7383                    cx,
 7384                    |selections| {
 7385                        selections.select_anchor_ranges([target..target]);
 7386                    },
 7387                );
 7388            }
 7389            InlineCompletion::Edit { edits, .. } => {
 7390                // Find an insertion that starts at the cursor position.
 7391                let snapshot = self.buffer.read(cx).snapshot(cx);
 7392                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7393                let insertion = edits.iter().find_map(|(range, text)| {
 7394                    let range = range.to_offset(&snapshot);
 7395                    if range.is_empty() && range.start == cursor_offset {
 7396                        Some(text)
 7397                    } else {
 7398                        None
 7399                    }
 7400                });
 7401
 7402                if let Some(text) = insertion {
 7403                    let mut partial_completion = text
 7404                        .chars()
 7405                        .by_ref()
 7406                        .take_while(|c| c.is_alphabetic())
 7407                        .collect::<String>();
 7408                    if partial_completion.is_empty() {
 7409                        partial_completion = text
 7410                            .chars()
 7411                            .by_ref()
 7412                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7413                            .collect::<String>();
 7414                    }
 7415
 7416                    cx.emit(EditorEvent::InputHandled {
 7417                        utf16_range_to_replace: None,
 7418                        text: partial_completion.clone().into(),
 7419                    });
 7420
 7421                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7422
 7423                    self.refresh_inline_completion(true, true, window, cx);
 7424                    cx.notify();
 7425                } else {
 7426                    self.accept_edit_prediction(&Default::default(), window, cx);
 7427                }
 7428            }
 7429        }
 7430    }
 7431
 7432    fn discard_inline_completion(
 7433        &mut self,
 7434        should_report_inline_completion_event: bool,
 7435        cx: &mut Context<Self>,
 7436    ) -> bool {
 7437        if should_report_inline_completion_event {
 7438            let completion_id = self
 7439                .active_inline_completion
 7440                .as_ref()
 7441                .and_then(|active_completion| active_completion.completion_id.clone());
 7442
 7443            self.report_inline_completion_event(completion_id, false, cx);
 7444        }
 7445
 7446        if let Some(provider) = self.edit_prediction_provider() {
 7447            provider.discard(cx);
 7448        }
 7449
 7450        self.take_active_inline_completion(cx)
 7451    }
 7452
 7453    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7454        let Some(provider) = self.edit_prediction_provider() else {
 7455            return;
 7456        };
 7457
 7458        let Some((_, buffer, _)) = self
 7459            .buffer
 7460            .read(cx)
 7461            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7462        else {
 7463            return;
 7464        };
 7465
 7466        let extension = buffer
 7467            .read(cx)
 7468            .file()
 7469            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7470
 7471        let event_type = match accepted {
 7472            true => "Edit Prediction Accepted",
 7473            false => "Edit Prediction Discarded",
 7474        };
 7475        telemetry::event!(
 7476            event_type,
 7477            provider = provider.name(),
 7478            prediction_id = id,
 7479            suggestion_accepted = accepted,
 7480            file_extension = extension,
 7481        );
 7482    }
 7483
 7484    pub fn has_active_inline_completion(&self) -> bool {
 7485        self.active_inline_completion.is_some()
 7486    }
 7487
 7488    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7489        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7490            return false;
 7491        };
 7492
 7493        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7494        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7495        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7496        true
 7497    }
 7498
 7499    /// Returns true when we're displaying the edit prediction popover below the cursor
 7500    /// like we are not previewing and the LSP autocomplete menu is visible
 7501    /// or we are in `when_holding_modifier` mode.
 7502    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7503        if self.edit_prediction_preview_is_active()
 7504            || !self.show_edit_predictions_in_menu()
 7505            || !self.edit_predictions_enabled()
 7506        {
 7507            return false;
 7508        }
 7509
 7510        if self.has_visible_completions_menu() {
 7511            return true;
 7512        }
 7513
 7514        has_completion && self.edit_prediction_requires_modifier()
 7515    }
 7516
 7517    fn handle_modifiers_changed(
 7518        &mut self,
 7519        modifiers: Modifiers,
 7520        position_map: &PositionMap,
 7521        window: &mut Window,
 7522        cx: &mut Context<Self>,
 7523    ) {
 7524        if self.show_edit_predictions_in_menu() {
 7525            self.update_edit_prediction_preview(&modifiers, window, cx);
 7526        }
 7527
 7528        self.update_selection_mode(&modifiers, position_map, window, cx);
 7529
 7530        let mouse_position = window.mouse_position();
 7531        if !position_map.text_hitbox.is_hovered(window) {
 7532            return;
 7533        }
 7534
 7535        self.update_hovered_link(
 7536            position_map.point_for_position(mouse_position),
 7537            &position_map.snapshot,
 7538            modifiers,
 7539            window,
 7540            cx,
 7541        )
 7542    }
 7543
 7544    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7545        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7546        if invert {
 7547            match multi_cursor_setting {
 7548                MultiCursorModifier::Alt => modifiers.alt,
 7549                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7550            }
 7551        } else {
 7552            match multi_cursor_setting {
 7553                MultiCursorModifier::Alt => modifiers.secondary(),
 7554                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7555            }
 7556        }
 7557    }
 7558
 7559    fn columnar_selection_mode(
 7560        modifiers: &Modifiers,
 7561        cx: &mut Context<Self>,
 7562    ) -> Option<ColumnarMode> {
 7563        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7564            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7565                Some(ColumnarMode::FromMouse)
 7566            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7567                Some(ColumnarMode::FromSelection)
 7568            } else {
 7569                None
 7570            }
 7571        } else {
 7572            None
 7573        }
 7574    }
 7575
 7576    fn update_selection_mode(
 7577        &mut self,
 7578        modifiers: &Modifiers,
 7579        position_map: &PositionMap,
 7580        window: &mut Window,
 7581        cx: &mut Context<Self>,
 7582    ) {
 7583        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7584            return;
 7585        };
 7586        if self.selections.pending.is_none() {
 7587            return;
 7588        }
 7589
 7590        let mouse_position = window.mouse_position();
 7591        let point_for_position = position_map.point_for_position(mouse_position);
 7592        let position = point_for_position.previous_valid;
 7593
 7594        self.select(
 7595            SelectPhase::BeginColumnar {
 7596                position,
 7597                reset: false,
 7598                mode,
 7599                goal_column: point_for_position.exact_unclipped.column(),
 7600            },
 7601            window,
 7602            cx,
 7603        );
 7604    }
 7605
 7606    fn update_edit_prediction_preview(
 7607        &mut self,
 7608        modifiers: &Modifiers,
 7609        window: &mut Window,
 7610        cx: &mut Context<Self>,
 7611    ) {
 7612        let mut modifiers_held = false;
 7613        if let Some(accept_keystroke) = self
 7614            .accept_edit_prediction_keybind(false, window, cx)
 7615            .keystroke()
 7616        {
 7617            modifiers_held = modifiers_held
 7618                || (&accept_keystroke.modifiers == modifiers
 7619                    && accept_keystroke.modifiers.modified());
 7620        };
 7621        if let Some(accept_partial_keystroke) = self
 7622            .accept_edit_prediction_keybind(true, window, cx)
 7623            .keystroke()
 7624        {
 7625            modifiers_held = modifiers_held
 7626                || (&accept_partial_keystroke.modifiers == modifiers
 7627                    && accept_partial_keystroke.modifiers.modified());
 7628        }
 7629
 7630        if modifiers_held {
 7631            if matches!(
 7632                self.edit_prediction_preview,
 7633                EditPredictionPreview::Inactive { .. }
 7634            ) {
 7635                self.edit_prediction_preview = EditPredictionPreview::Active {
 7636                    previous_scroll_position: None,
 7637                    since: Instant::now(),
 7638                };
 7639
 7640                self.update_visible_inline_completion(window, cx);
 7641                cx.notify();
 7642            }
 7643        } else if let EditPredictionPreview::Active {
 7644            previous_scroll_position,
 7645            since,
 7646        } = self.edit_prediction_preview
 7647        {
 7648            if let (Some(previous_scroll_position), Some(position_map)) =
 7649                (previous_scroll_position, self.last_position_map.as_ref())
 7650            {
 7651                self.set_scroll_position(
 7652                    previous_scroll_position
 7653                        .scroll_position(&position_map.snapshot.display_snapshot),
 7654                    window,
 7655                    cx,
 7656                );
 7657            }
 7658
 7659            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7660                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7661            };
 7662            self.clear_row_highlights::<EditPredictionPreview>();
 7663            self.update_visible_inline_completion(window, cx);
 7664            cx.notify();
 7665        }
 7666    }
 7667
 7668    fn update_visible_inline_completion(
 7669        &mut self,
 7670        _window: &mut Window,
 7671        cx: &mut Context<Self>,
 7672    ) -> Option<()> {
 7673        let selection = self.selections.newest_anchor();
 7674        let cursor = selection.head();
 7675        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7676        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7677        let excerpt_id = cursor.excerpt_id;
 7678
 7679        let show_in_menu = self.show_edit_predictions_in_menu();
 7680        let completions_menu_has_precedence = !show_in_menu
 7681            && (self.context_menu.borrow().is_some()
 7682                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7683
 7684        if completions_menu_has_precedence
 7685            || !offset_selection.is_empty()
 7686            || self
 7687                .active_inline_completion
 7688                .as_ref()
 7689                .map_or(false, |completion| {
 7690                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7691                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7692                    !invalidation_range.contains(&offset_selection.head())
 7693                })
 7694        {
 7695            self.discard_inline_completion(false, cx);
 7696            return None;
 7697        }
 7698
 7699        self.take_active_inline_completion(cx);
 7700        let Some(provider) = self.edit_prediction_provider() else {
 7701            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7702            return None;
 7703        };
 7704
 7705        let (buffer, cursor_buffer_position) =
 7706            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7707
 7708        self.edit_prediction_settings =
 7709            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7710
 7711        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7712
 7713        if self.edit_prediction_indent_conflict {
 7714            let cursor_point = cursor.to_point(&multibuffer);
 7715
 7716            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7717
 7718            if let Some((_, indent)) = indents.iter().next() {
 7719                if indent.len == cursor_point.column {
 7720                    self.edit_prediction_indent_conflict = false;
 7721                }
 7722            }
 7723        }
 7724
 7725        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7726        let edits = inline_completion
 7727            .edits
 7728            .into_iter()
 7729            .flat_map(|(range, new_text)| {
 7730                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7731                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7732                Some((start..end, new_text))
 7733            })
 7734            .collect::<Vec<_>>();
 7735        if edits.is_empty() {
 7736            return None;
 7737        }
 7738
 7739        let first_edit_start = edits.first().unwrap().0.start;
 7740        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7741        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7742
 7743        let last_edit_end = edits.last().unwrap().0.end;
 7744        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7745        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7746
 7747        let cursor_row = cursor.to_point(&multibuffer).row;
 7748
 7749        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7750
 7751        let mut inlay_ids = Vec::new();
 7752        let invalidation_row_range;
 7753        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7754            Some(cursor_row..edit_end_row)
 7755        } else if cursor_row > edit_end_row {
 7756            Some(edit_start_row..cursor_row)
 7757        } else {
 7758            None
 7759        };
 7760        let is_move =
 7761            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7762        let completion = if is_move {
 7763            invalidation_row_range =
 7764                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7765            let target = first_edit_start;
 7766            InlineCompletion::Move { target, snapshot }
 7767        } else {
 7768            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7769                && !self.inline_completions_hidden_for_vim_mode;
 7770
 7771            if show_completions_in_buffer {
 7772                if edits
 7773                    .iter()
 7774                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7775                {
 7776                    let mut inlays = Vec::new();
 7777                    for (range, new_text) in &edits {
 7778                        let inlay = Inlay::inline_completion(
 7779                            post_inc(&mut self.next_inlay_id),
 7780                            range.start,
 7781                            new_text.as_str(),
 7782                        );
 7783                        inlay_ids.push(inlay.id);
 7784                        inlays.push(inlay);
 7785                    }
 7786
 7787                    self.splice_inlays(&[], inlays, cx);
 7788                } else {
 7789                    let background_color = cx.theme().status().deleted_background;
 7790                    self.highlight_text::<InlineCompletionHighlight>(
 7791                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7792                        HighlightStyle {
 7793                            background_color: Some(background_color),
 7794                            ..Default::default()
 7795                        },
 7796                        cx,
 7797                    );
 7798                }
 7799            }
 7800
 7801            invalidation_row_range = edit_start_row..edit_end_row;
 7802
 7803            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7804                if provider.show_tab_accept_marker() {
 7805                    EditDisplayMode::TabAccept
 7806                } else {
 7807                    EditDisplayMode::Inline
 7808                }
 7809            } else {
 7810                EditDisplayMode::DiffPopover
 7811            };
 7812
 7813            InlineCompletion::Edit {
 7814                edits,
 7815                edit_preview: inline_completion.edit_preview,
 7816                display_mode,
 7817                snapshot,
 7818            }
 7819        };
 7820
 7821        let invalidation_range = multibuffer
 7822            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7823            ..multibuffer.anchor_after(Point::new(
 7824                invalidation_row_range.end,
 7825                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7826            ));
 7827
 7828        self.stale_inline_completion_in_menu = None;
 7829        self.active_inline_completion = Some(InlineCompletionState {
 7830            inlay_ids,
 7831            completion,
 7832            completion_id: inline_completion.id,
 7833            invalidation_range,
 7834        });
 7835
 7836        cx.notify();
 7837
 7838        Some(())
 7839    }
 7840
 7841    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7842        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7843    }
 7844
 7845    fn clear_tasks(&mut self) {
 7846        self.tasks.clear()
 7847    }
 7848
 7849    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7850        if self.tasks.insert(key, value).is_some() {
 7851            // This case should hopefully be rare, but just in case...
 7852            log::error!(
 7853                "multiple different run targets found on a single line, only the last target will be rendered"
 7854            )
 7855        }
 7856    }
 7857
 7858    /// Get all display points of breakpoints that will be rendered within editor
 7859    ///
 7860    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7861    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7862    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7863    fn active_breakpoints(
 7864        &self,
 7865        range: Range<DisplayRow>,
 7866        window: &mut Window,
 7867        cx: &mut Context<Self>,
 7868    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7869        let mut breakpoint_display_points = HashMap::default();
 7870
 7871        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7872            return breakpoint_display_points;
 7873        };
 7874
 7875        let snapshot = self.snapshot(window, cx);
 7876
 7877        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7878        let Some(project) = self.project.as_ref() else {
 7879            return breakpoint_display_points;
 7880        };
 7881
 7882        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7883            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7884
 7885        for (buffer_snapshot, range, excerpt_id) in
 7886            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7887        {
 7888            let Some(buffer) = project
 7889                .read(cx)
 7890                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7891            else {
 7892                continue;
 7893            };
 7894            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7895                &buffer,
 7896                Some(
 7897                    buffer_snapshot.anchor_before(range.start)
 7898                        ..buffer_snapshot.anchor_after(range.end),
 7899                ),
 7900                buffer_snapshot,
 7901                cx,
 7902            );
 7903            for (breakpoint, state) in breakpoints {
 7904                let multi_buffer_anchor =
 7905                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7906                let position = multi_buffer_anchor
 7907                    .to_point(&multi_buffer_snapshot)
 7908                    .to_display_point(&snapshot);
 7909
 7910                breakpoint_display_points.insert(
 7911                    position.row(),
 7912                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7913                );
 7914            }
 7915        }
 7916
 7917        breakpoint_display_points
 7918    }
 7919
 7920    fn breakpoint_context_menu(
 7921        &self,
 7922        anchor: Anchor,
 7923        window: &mut Window,
 7924        cx: &mut Context<Self>,
 7925    ) -> Entity<ui::ContextMenu> {
 7926        let weak_editor = cx.weak_entity();
 7927        let focus_handle = self.focus_handle(cx);
 7928
 7929        let row = self
 7930            .buffer
 7931            .read(cx)
 7932            .snapshot(cx)
 7933            .summary_for_anchor::<Point>(&anchor)
 7934            .row;
 7935
 7936        let breakpoint = self
 7937            .breakpoint_at_row(row, window, cx)
 7938            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7939
 7940        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7941            "Edit Log Breakpoint"
 7942        } else {
 7943            "Set Log Breakpoint"
 7944        };
 7945
 7946        let condition_breakpoint_msg = if breakpoint
 7947            .as_ref()
 7948            .is_some_and(|bp| bp.1.condition.is_some())
 7949        {
 7950            "Edit Condition Breakpoint"
 7951        } else {
 7952            "Set Condition Breakpoint"
 7953        };
 7954
 7955        let hit_condition_breakpoint_msg = if breakpoint
 7956            .as_ref()
 7957            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7958        {
 7959            "Edit Hit Condition Breakpoint"
 7960        } else {
 7961            "Set Hit Condition Breakpoint"
 7962        };
 7963
 7964        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7965            "Unset Breakpoint"
 7966        } else {
 7967            "Set Breakpoint"
 7968        };
 7969
 7970        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7971
 7972        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7973            BreakpointState::Enabled => Some("Disable"),
 7974            BreakpointState::Disabled => Some("Enable"),
 7975        });
 7976
 7977        let (anchor, breakpoint) =
 7978            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7979
 7980        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7981            menu.on_blur_subscription(Subscription::new(|| {}))
 7982                .context(focus_handle)
 7983                .when(run_to_cursor, |this| {
 7984                    let weak_editor = weak_editor.clone();
 7985                    this.entry("Run to cursor", None, move |window, cx| {
 7986                        weak_editor
 7987                            .update(cx, |editor, cx| {
 7988                                editor.change_selections(
 7989                                    SelectionEffects::no_scroll(),
 7990                                    window,
 7991                                    cx,
 7992                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 7993                                );
 7994                            })
 7995                            .ok();
 7996
 7997                        window.dispatch_action(Box::new(RunToCursor), cx);
 7998                    })
 7999                    .separator()
 8000                })
 8001                .when_some(toggle_state_msg, |this, msg| {
 8002                    this.entry(msg, None, {
 8003                        let weak_editor = weak_editor.clone();
 8004                        let breakpoint = breakpoint.clone();
 8005                        move |_window, cx| {
 8006                            weak_editor
 8007                                .update(cx, |this, cx| {
 8008                                    this.edit_breakpoint_at_anchor(
 8009                                        anchor,
 8010                                        breakpoint.as_ref().clone(),
 8011                                        BreakpointEditAction::InvertState,
 8012                                        cx,
 8013                                    );
 8014                                })
 8015                                .log_err();
 8016                        }
 8017                    })
 8018                })
 8019                .entry(set_breakpoint_msg, None, {
 8020                    let weak_editor = weak_editor.clone();
 8021                    let breakpoint = breakpoint.clone();
 8022                    move |_window, cx| {
 8023                        weak_editor
 8024                            .update(cx, |this, cx| {
 8025                                this.edit_breakpoint_at_anchor(
 8026                                    anchor,
 8027                                    breakpoint.as_ref().clone(),
 8028                                    BreakpointEditAction::Toggle,
 8029                                    cx,
 8030                                );
 8031                            })
 8032                            .log_err();
 8033                    }
 8034                })
 8035                .entry(log_breakpoint_msg, None, {
 8036                    let breakpoint = breakpoint.clone();
 8037                    let weak_editor = weak_editor.clone();
 8038                    move |window, cx| {
 8039                        weak_editor
 8040                            .update(cx, |this, cx| {
 8041                                this.add_edit_breakpoint_block(
 8042                                    anchor,
 8043                                    breakpoint.as_ref(),
 8044                                    BreakpointPromptEditAction::Log,
 8045                                    window,
 8046                                    cx,
 8047                                );
 8048                            })
 8049                            .log_err();
 8050                    }
 8051                })
 8052                .entry(condition_breakpoint_msg, None, {
 8053                    let breakpoint = breakpoint.clone();
 8054                    let weak_editor = weak_editor.clone();
 8055                    move |window, cx| {
 8056                        weak_editor
 8057                            .update(cx, |this, cx| {
 8058                                this.add_edit_breakpoint_block(
 8059                                    anchor,
 8060                                    breakpoint.as_ref(),
 8061                                    BreakpointPromptEditAction::Condition,
 8062                                    window,
 8063                                    cx,
 8064                                );
 8065                            })
 8066                            .log_err();
 8067                    }
 8068                })
 8069                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8070                    weak_editor
 8071                        .update(cx, |this, cx| {
 8072                            this.add_edit_breakpoint_block(
 8073                                anchor,
 8074                                breakpoint.as_ref(),
 8075                                BreakpointPromptEditAction::HitCondition,
 8076                                window,
 8077                                cx,
 8078                            );
 8079                        })
 8080                        .log_err();
 8081                })
 8082        })
 8083    }
 8084
 8085    fn render_breakpoint(
 8086        &self,
 8087        position: Anchor,
 8088        row: DisplayRow,
 8089        breakpoint: &Breakpoint,
 8090        state: Option<BreakpointSessionState>,
 8091        cx: &mut Context<Self>,
 8092    ) -> IconButton {
 8093        let is_rejected = state.is_some_and(|s| !s.verified);
 8094        // Is it a breakpoint that shows up when hovering over gutter?
 8095        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8096            (false, false),
 8097            |PhantomBreakpointIndicator {
 8098                 is_active,
 8099                 display_row,
 8100                 collides_with_existing_breakpoint,
 8101             }| {
 8102                (
 8103                    is_active && display_row == row,
 8104                    collides_with_existing_breakpoint,
 8105                )
 8106            },
 8107        );
 8108
 8109        let (color, icon) = {
 8110            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8111                (false, false) => ui::IconName::DebugBreakpoint,
 8112                (true, false) => ui::IconName::DebugLogBreakpoint,
 8113                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8114                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8115            };
 8116
 8117            let color = if is_phantom {
 8118                Color::Hint
 8119            } else if is_rejected {
 8120                Color::Disabled
 8121            } else {
 8122                Color::Debugger
 8123            };
 8124
 8125            (color, icon)
 8126        };
 8127
 8128        let breakpoint = Arc::from(breakpoint.clone());
 8129
 8130        let alt_as_text = gpui::Keystroke {
 8131            modifiers: Modifiers::secondary_key(),
 8132            ..Default::default()
 8133        };
 8134        let primary_action_text = if breakpoint.is_disabled() {
 8135            "Enable breakpoint"
 8136        } else if is_phantom && !collides_with_existing {
 8137            "Set breakpoint"
 8138        } else {
 8139            "Unset breakpoint"
 8140        };
 8141        let focus_handle = self.focus_handle.clone();
 8142
 8143        let meta = if is_rejected {
 8144            SharedString::from("No executable code is associated with this line.")
 8145        } else if collides_with_existing && !breakpoint.is_disabled() {
 8146            SharedString::from(format!(
 8147                "{alt_as_text}-click to disable,\nright-click for more options."
 8148            ))
 8149        } else {
 8150            SharedString::from("Right-click for more options.")
 8151        };
 8152        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8153            .icon_size(IconSize::XSmall)
 8154            .size(ui::ButtonSize::None)
 8155            .when(is_rejected, |this| {
 8156                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8157            })
 8158            .icon_color(color)
 8159            .style(ButtonStyle::Transparent)
 8160            .on_click(cx.listener({
 8161                let breakpoint = breakpoint.clone();
 8162
 8163                move |editor, event: &ClickEvent, window, cx| {
 8164                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8165                        BreakpointEditAction::InvertState
 8166                    } else {
 8167                        BreakpointEditAction::Toggle
 8168                    };
 8169
 8170                    window.focus(&editor.focus_handle(cx));
 8171                    editor.edit_breakpoint_at_anchor(
 8172                        position,
 8173                        breakpoint.as_ref().clone(),
 8174                        edit_action,
 8175                        cx,
 8176                    );
 8177                }
 8178            }))
 8179            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8180                editor.set_breakpoint_context_menu(
 8181                    row,
 8182                    Some(position),
 8183                    event.down.position,
 8184                    window,
 8185                    cx,
 8186                );
 8187            }))
 8188            .tooltip(move |window, cx| {
 8189                Tooltip::with_meta_in(
 8190                    primary_action_text,
 8191                    Some(&ToggleBreakpoint),
 8192                    meta.clone(),
 8193                    &focus_handle,
 8194                    window,
 8195                    cx,
 8196                )
 8197            })
 8198    }
 8199
 8200    fn build_tasks_context(
 8201        project: &Entity<Project>,
 8202        buffer: &Entity<Buffer>,
 8203        buffer_row: u32,
 8204        tasks: &Arc<RunnableTasks>,
 8205        cx: &mut Context<Self>,
 8206    ) -> Task<Option<task::TaskContext>> {
 8207        let position = Point::new(buffer_row, tasks.column);
 8208        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8209        let location = Location {
 8210            buffer: buffer.clone(),
 8211            range: range_start..range_start,
 8212        };
 8213        // Fill in the environmental variables from the tree-sitter captures
 8214        let mut captured_task_variables = TaskVariables::default();
 8215        for (capture_name, value) in tasks.extra_variables.clone() {
 8216            captured_task_variables.insert(
 8217                task::VariableName::Custom(capture_name.into()),
 8218                value.clone(),
 8219            );
 8220        }
 8221        project.update(cx, |project, cx| {
 8222            project.task_store().update(cx, |task_store, cx| {
 8223                task_store.task_context_for_location(captured_task_variables, location, cx)
 8224            })
 8225        })
 8226    }
 8227
 8228    pub fn spawn_nearest_task(
 8229        &mut self,
 8230        action: &SpawnNearestTask,
 8231        window: &mut Window,
 8232        cx: &mut Context<Self>,
 8233    ) {
 8234        let Some((workspace, _)) = self.workspace.clone() else {
 8235            return;
 8236        };
 8237        let Some(project) = self.project.clone() else {
 8238            return;
 8239        };
 8240
 8241        // Try to find a closest, enclosing node using tree-sitter that has a task
 8242        let Some((buffer, buffer_row, tasks)) = self
 8243            .find_enclosing_node_task(cx)
 8244            // Or find the task that's closest in row-distance.
 8245            .or_else(|| self.find_closest_task(cx))
 8246        else {
 8247            return;
 8248        };
 8249
 8250        let reveal_strategy = action.reveal;
 8251        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8252        cx.spawn_in(window, async move |_, cx| {
 8253            let context = task_context.await?;
 8254            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8255
 8256            let resolved = &mut resolved_task.resolved;
 8257            resolved.reveal = reveal_strategy;
 8258
 8259            workspace
 8260                .update_in(cx, |workspace, window, cx| {
 8261                    workspace.schedule_resolved_task(
 8262                        task_source_kind,
 8263                        resolved_task,
 8264                        false,
 8265                        window,
 8266                        cx,
 8267                    );
 8268                })
 8269                .ok()
 8270        })
 8271        .detach();
 8272    }
 8273
 8274    fn find_closest_task(
 8275        &mut self,
 8276        cx: &mut Context<Self>,
 8277    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8278        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8279
 8280        let ((buffer_id, row), tasks) = self
 8281            .tasks
 8282            .iter()
 8283            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8284
 8285        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8286        let tasks = Arc::new(tasks.to_owned());
 8287        Some((buffer, *row, tasks))
 8288    }
 8289
 8290    fn find_enclosing_node_task(
 8291        &mut self,
 8292        cx: &mut Context<Self>,
 8293    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8294        let snapshot = self.buffer.read(cx).snapshot(cx);
 8295        let offset = self.selections.newest::<usize>(cx).head();
 8296        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8297        let buffer_id = excerpt.buffer().remote_id();
 8298
 8299        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8300        let mut cursor = layer.node().walk();
 8301
 8302        while cursor.goto_first_child_for_byte(offset).is_some() {
 8303            if cursor.node().end_byte() == offset {
 8304                cursor.goto_next_sibling();
 8305            }
 8306        }
 8307
 8308        // Ascend to the smallest ancestor that contains the range and has a task.
 8309        loop {
 8310            let node = cursor.node();
 8311            let node_range = node.byte_range();
 8312            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8313
 8314            // Check if this node contains our offset
 8315            if node_range.start <= offset && node_range.end >= offset {
 8316                // If it contains offset, check for task
 8317                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8318                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8319                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8320                }
 8321            }
 8322
 8323            if !cursor.goto_parent() {
 8324                break;
 8325            }
 8326        }
 8327        None
 8328    }
 8329
 8330    fn render_run_indicator(
 8331        &self,
 8332        _style: &EditorStyle,
 8333        is_active: bool,
 8334        row: DisplayRow,
 8335        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8336        cx: &mut Context<Self>,
 8337    ) -> IconButton {
 8338        let color = Color::Muted;
 8339        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8340
 8341        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 8342            .shape(ui::IconButtonShape::Square)
 8343            .icon_size(IconSize::XSmall)
 8344            .icon_color(color)
 8345            .toggle_state(is_active)
 8346            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8347                let quick_launch = e.down.button == MouseButton::Left;
 8348                window.focus(&editor.focus_handle(cx));
 8349                editor.toggle_code_actions(
 8350                    &ToggleCodeActions {
 8351                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 8352                        quick_launch,
 8353                    },
 8354                    window,
 8355                    cx,
 8356                );
 8357            }))
 8358            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8359                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 8360            }))
 8361    }
 8362
 8363    pub fn context_menu_visible(&self) -> bool {
 8364        !self.edit_prediction_preview_is_active()
 8365            && self
 8366                .context_menu
 8367                .borrow()
 8368                .as_ref()
 8369                .map_or(false, |menu| menu.visible())
 8370    }
 8371
 8372    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8373        self.context_menu
 8374            .borrow()
 8375            .as_ref()
 8376            .map(|menu| menu.origin())
 8377    }
 8378
 8379    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8380        self.context_menu_options = Some(options);
 8381    }
 8382
 8383    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8384    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8385
 8386    fn render_edit_prediction_popover(
 8387        &mut self,
 8388        text_bounds: &Bounds<Pixels>,
 8389        content_origin: gpui::Point<Pixels>,
 8390        right_margin: Pixels,
 8391        editor_snapshot: &EditorSnapshot,
 8392        visible_row_range: Range<DisplayRow>,
 8393        scroll_top: f32,
 8394        scroll_bottom: f32,
 8395        line_layouts: &[LineWithInvisibles],
 8396        line_height: Pixels,
 8397        scroll_pixel_position: gpui::Point<Pixels>,
 8398        newest_selection_head: Option<DisplayPoint>,
 8399        editor_width: Pixels,
 8400        style: &EditorStyle,
 8401        window: &mut Window,
 8402        cx: &mut App,
 8403    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8404        if self.mode().is_minimap() {
 8405            return None;
 8406        }
 8407        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8408
 8409        if self.edit_prediction_visible_in_cursor_popover(true) {
 8410            return None;
 8411        }
 8412
 8413        match &active_inline_completion.completion {
 8414            InlineCompletion::Move { target, .. } => {
 8415                let target_display_point = target.to_display_point(editor_snapshot);
 8416
 8417                if self.edit_prediction_requires_modifier() {
 8418                    if !self.edit_prediction_preview_is_active() {
 8419                        return None;
 8420                    }
 8421
 8422                    self.render_edit_prediction_modifier_jump_popover(
 8423                        text_bounds,
 8424                        content_origin,
 8425                        visible_row_range,
 8426                        line_layouts,
 8427                        line_height,
 8428                        scroll_pixel_position,
 8429                        newest_selection_head,
 8430                        target_display_point,
 8431                        window,
 8432                        cx,
 8433                    )
 8434                } else {
 8435                    self.render_edit_prediction_eager_jump_popover(
 8436                        text_bounds,
 8437                        content_origin,
 8438                        editor_snapshot,
 8439                        visible_row_range,
 8440                        scroll_top,
 8441                        scroll_bottom,
 8442                        line_height,
 8443                        scroll_pixel_position,
 8444                        target_display_point,
 8445                        editor_width,
 8446                        window,
 8447                        cx,
 8448                    )
 8449                }
 8450            }
 8451            InlineCompletion::Edit {
 8452                display_mode: EditDisplayMode::Inline,
 8453                ..
 8454            } => None,
 8455            InlineCompletion::Edit {
 8456                display_mode: EditDisplayMode::TabAccept,
 8457                edits,
 8458                ..
 8459            } => {
 8460                let range = &edits.first()?.0;
 8461                let target_display_point = range.end.to_display_point(editor_snapshot);
 8462
 8463                self.render_edit_prediction_end_of_line_popover(
 8464                    "Accept",
 8465                    editor_snapshot,
 8466                    visible_row_range,
 8467                    target_display_point,
 8468                    line_height,
 8469                    scroll_pixel_position,
 8470                    content_origin,
 8471                    editor_width,
 8472                    window,
 8473                    cx,
 8474                )
 8475            }
 8476            InlineCompletion::Edit {
 8477                edits,
 8478                edit_preview,
 8479                display_mode: EditDisplayMode::DiffPopover,
 8480                snapshot,
 8481            } => self.render_edit_prediction_diff_popover(
 8482                text_bounds,
 8483                content_origin,
 8484                right_margin,
 8485                editor_snapshot,
 8486                visible_row_range,
 8487                line_layouts,
 8488                line_height,
 8489                scroll_pixel_position,
 8490                newest_selection_head,
 8491                editor_width,
 8492                style,
 8493                edits,
 8494                edit_preview,
 8495                snapshot,
 8496                window,
 8497                cx,
 8498            ),
 8499        }
 8500    }
 8501
 8502    fn render_edit_prediction_modifier_jump_popover(
 8503        &mut self,
 8504        text_bounds: &Bounds<Pixels>,
 8505        content_origin: gpui::Point<Pixels>,
 8506        visible_row_range: Range<DisplayRow>,
 8507        line_layouts: &[LineWithInvisibles],
 8508        line_height: Pixels,
 8509        scroll_pixel_position: gpui::Point<Pixels>,
 8510        newest_selection_head: Option<DisplayPoint>,
 8511        target_display_point: DisplayPoint,
 8512        window: &mut Window,
 8513        cx: &mut App,
 8514    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8515        let scrolled_content_origin =
 8516            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8517
 8518        const SCROLL_PADDING_Y: Pixels = px(12.);
 8519
 8520        if target_display_point.row() < visible_row_range.start {
 8521            return self.render_edit_prediction_scroll_popover(
 8522                |_| SCROLL_PADDING_Y,
 8523                IconName::ArrowUp,
 8524                visible_row_range,
 8525                line_layouts,
 8526                newest_selection_head,
 8527                scrolled_content_origin,
 8528                window,
 8529                cx,
 8530            );
 8531        } else if target_display_point.row() >= visible_row_range.end {
 8532            return self.render_edit_prediction_scroll_popover(
 8533                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8534                IconName::ArrowDown,
 8535                visible_row_range,
 8536                line_layouts,
 8537                newest_selection_head,
 8538                scrolled_content_origin,
 8539                window,
 8540                cx,
 8541            );
 8542        }
 8543
 8544        const POLE_WIDTH: Pixels = px(2.);
 8545
 8546        let line_layout =
 8547            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8548        let target_column = target_display_point.column() as usize;
 8549
 8550        let target_x = line_layout.x_for_index(target_column);
 8551        let target_y =
 8552            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8553
 8554        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8555
 8556        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8557        border_color.l += 0.001;
 8558
 8559        let mut element = v_flex()
 8560            .items_end()
 8561            .when(flag_on_right, |el| el.items_start())
 8562            .child(if flag_on_right {
 8563                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8564                    .rounded_bl(px(0.))
 8565                    .rounded_tl(px(0.))
 8566                    .border_l_2()
 8567                    .border_color(border_color)
 8568            } else {
 8569                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8570                    .rounded_br(px(0.))
 8571                    .rounded_tr(px(0.))
 8572                    .border_r_2()
 8573                    .border_color(border_color)
 8574            })
 8575            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8576            .into_any();
 8577
 8578        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8579
 8580        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8581            - point(
 8582                if flag_on_right {
 8583                    POLE_WIDTH
 8584                } else {
 8585                    size.width - POLE_WIDTH
 8586                },
 8587                size.height - line_height,
 8588            );
 8589
 8590        origin.x = origin.x.max(content_origin.x);
 8591
 8592        element.prepaint_at(origin, window, cx);
 8593
 8594        Some((element, origin))
 8595    }
 8596
 8597    fn render_edit_prediction_scroll_popover(
 8598        &mut self,
 8599        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8600        scroll_icon: IconName,
 8601        visible_row_range: Range<DisplayRow>,
 8602        line_layouts: &[LineWithInvisibles],
 8603        newest_selection_head: Option<DisplayPoint>,
 8604        scrolled_content_origin: gpui::Point<Pixels>,
 8605        window: &mut Window,
 8606        cx: &mut App,
 8607    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8608        let mut element = self
 8609            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8610            .into_any();
 8611
 8612        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8613
 8614        let cursor = newest_selection_head?;
 8615        let cursor_row_layout =
 8616            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8617        let cursor_column = cursor.column() as usize;
 8618
 8619        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8620
 8621        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8622
 8623        element.prepaint_at(origin, window, cx);
 8624        Some((element, origin))
 8625    }
 8626
 8627    fn render_edit_prediction_eager_jump_popover(
 8628        &mut self,
 8629        text_bounds: &Bounds<Pixels>,
 8630        content_origin: gpui::Point<Pixels>,
 8631        editor_snapshot: &EditorSnapshot,
 8632        visible_row_range: Range<DisplayRow>,
 8633        scroll_top: f32,
 8634        scroll_bottom: f32,
 8635        line_height: Pixels,
 8636        scroll_pixel_position: gpui::Point<Pixels>,
 8637        target_display_point: DisplayPoint,
 8638        editor_width: Pixels,
 8639        window: &mut Window,
 8640        cx: &mut App,
 8641    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8642        if target_display_point.row().as_f32() < scroll_top {
 8643            let mut element = self
 8644                .render_edit_prediction_line_popover(
 8645                    "Jump to Edit",
 8646                    Some(IconName::ArrowUp),
 8647                    window,
 8648                    cx,
 8649                )?
 8650                .into_any();
 8651
 8652            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8653            let offset = point(
 8654                (text_bounds.size.width - size.width) / 2.,
 8655                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8656            );
 8657
 8658            let origin = text_bounds.origin + offset;
 8659            element.prepaint_at(origin, window, cx);
 8660            Some((element, origin))
 8661        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8662            let mut element = self
 8663                .render_edit_prediction_line_popover(
 8664                    "Jump to Edit",
 8665                    Some(IconName::ArrowDown),
 8666                    window,
 8667                    cx,
 8668                )?
 8669                .into_any();
 8670
 8671            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8672            let offset = point(
 8673                (text_bounds.size.width - size.width) / 2.,
 8674                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8675            );
 8676
 8677            let origin = text_bounds.origin + offset;
 8678            element.prepaint_at(origin, window, cx);
 8679            Some((element, origin))
 8680        } else {
 8681            self.render_edit_prediction_end_of_line_popover(
 8682                "Jump to Edit",
 8683                editor_snapshot,
 8684                visible_row_range,
 8685                target_display_point,
 8686                line_height,
 8687                scroll_pixel_position,
 8688                content_origin,
 8689                editor_width,
 8690                window,
 8691                cx,
 8692            )
 8693        }
 8694    }
 8695
 8696    fn render_edit_prediction_end_of_line_popover(
 8697        self: &mut Editor,
 8698        label: &'static str,
 8699        editor_snapshot: &EditorSnapshot,
 8700        visible_row_range: Range<DisplayRow>,
 8701        target_display_point: DisplayPoint,
 8702        line_height: Pixels,
 8703        scroll_pixel_position: gpui::Point<Pixels>,
 8704        content_origin: gpui::Point<Pixels>,
 8705        editor_width: Pixels,
 8706        window: &mut Window,
 8707        cx: &mut App,
 8708    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8709        let target_line_end = DisplayPoint::new(
 8710            target_display_point.row(),
 8711            editor_snapshot.line_len(target_display_point.row()),
 8712        );
 8713
 8714        let mut element = self
 8715            .render_edit_prediction_line_popover(label, None, window, cx)?
 8716            .into_any();
 8717
 8718        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8719
 8720        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8721
 8722        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8723        let mut origin = start_point
 8724            + line_origin
 8725            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8726        origin.x = origin.x.max(content_origin.x);
 8727
 8728        let max_x = content_origin.x + editor_width - size.width;
 8729
 8730        if origin.x > max_x {
 8731            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8732
 8733            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8734                origin.y += offset;
 8735                IconName::ArrowUp
 8736            } else {
 8737                origin.y -= offset;
 8738                IconName::ArrowDown
 8739            };
 8740
 8741            element = self
 8742                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8743                .into_any();
 8744
 8745            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8746
 8747            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8748        }
 8749
 8750        element.prepaint_at(origin, window, cx);
 8751        Some((element, origin))
 8752    }
 8753
 8754    fn render_edit_prediction_diff_popover(
 8755        self: &Editor,
 8756        text_bounds: &Bounds<Pixels>,
 8757        content_origin: gpui::Point<Pixels>,
 8758        right_margin: Pixels,
 8759        editor_snapshot: &EditorSnapshot,
 8760        visible_row_range: Range<DisplayRow>,
 8761        line_layouts: &[LineWithInvisibles],
 8762        line_height: Pixels,
 8763        scroll_pixel_position: gpui::Point<Pixels>,
 8764        newest_selection_head: Option<DisplayPoint>,
 8765        editor_width: Pixels,
 8766        style: &EditorStyle,
 8767        edits: &Vec<(Range<Anchor>, String)>,
 8768        edit_preview: &Option<language::EditPreview>,
 8769        snapshot: &language::BufferSnapshot,
 8770        window: &mut Window,
 8771        cx: &mut App,
 8772    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8773        let edit_start = edits
 8774            .first()
 8775            .unwrap()
 8776            .0
 8777            .start
 8778            .to_display_point(editor_snapshot);
 8779        let edit_end = edits
 8780            .last()
 8781            .unwrap()
 8782            .0
 8783            .end
 8784            .to_display_point(editor_snapshot);
 8785
 8786        let is_visible = visible_row_range.contains(&edit_start.row())
 8787            || visible_row_range.contains(&edit_end.row());
 8788        if !is_visible {
 8789            return None;
 8790        }
 8791
 8792        let highlighted_edits =
 8793            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8794
 8795        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8796        let line_count = highlighted_edits.text.lines().count();
 8797
 8798        const BORDER_WIDTH: Pixels = px(1.);
 8799
 8800        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8801        let has_keybind = keybind.is_some();
 8802
 8803        let mut element = h_flex()
 8804            .items_start()
 8805            .child(
 8806                h_flex()
 8807                    .bg(cx.theme().colors().editor_background)
 8808                    .border(BORDER_WIDTH)
 8809                    .shadow_xs()
 8810                    .border_color(cx.theme().colors().border)
 8811                    .rounded_l_lg()
 8812                    .when(line_count > 1, |el| el.rounded_br_lg())
 8813                    .pr_1()
 8814                    .child(styled_text),
 8815            )
 8816            .child(
 8817                h_flex()
 8818                    .h(line_height + BORDER_WIDTH * 2.)
 8819                    .px_1p5()
 8820                    .gap_1()
 8821                    // Workaround: For some reason, there's a gap if we don't do this
 8822                    .ml(-BORDER_WIDTH)
 8823                    .shadow(vec![gpui::BoxShadow {
 8824                        color: gpui::black().opacity(0.05),
 8825                        offset: point(px(1.), px(1.)),
 8826                        blur_radius: px(2.),
 8827                        spread_radius: px(0.),
 8828                    }])
 8829                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8830                    .border(BORDER_WIDTH)
 8831                    .border_color(cx.theme().colors().border)
 8832                    .rounded_r_lg()
 8833                    .id("edit_prediction_diff_popover_keybind")
 8834                    .when(!has_keybind, |el| {
 8835                        let status_colors = cx.theme().status();
 8836
 8837                        el.bg(status_colors.error_background)
 8838                            .border_color(status_colors.error.opacity(0.6))
 8839                            .child(Icon::new(IconName::Info).color(Color::Error))
 8840                            .cursor_default()
 8841                            .hoverable_tooltip(move |_window, cx| {
 8842                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8843                            })
 8844                    })
 8845                    .children(keybind),
 8846            )
 8847            .into_any();
 8848
 8849        let longest_row =
 8850            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8851        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8852            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8853        } else {
 8854            layout_line(
 8855                longest_row,
 8856                editor_snapshot,
 8857                style,
 8858                editor_width,
 8859                |_| false,
 8860                window,
 8861                cx,
 8862            )
 8863            .width
 8864        };
 8865
 8866        let viewport_bounds =
 8867            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8868                right: -right_margin,
 8869                ..Default::default()
 8870            });
 8871
 8872        let x_after_longest =
 8873            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8874                - scroll_pixel_position.x;
 8875
 8876        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8877
 8878        // Fully visible if it can be displayed within the window (allow overlapping other
 8879        // panes). However, this is only allowed if the popover starts within text_bounds.
 8880        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8881            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8882
 8883        let mut origin = if can_position_to_the_right {
 8884            point(
 8885                x_after_longest,
 8886                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8887                    - scroll_pixel_position.y,
 8888            )
 8889        } else {
 8890            let cursor_row = newest_selection_head.map(|head| head.row());
 8891            let above_edit = edit_start
 8892                .row()
 8893                .0
 8894                .checked_sub(line_count as u32)
 8895                .map(DisplayRow);
 8896            let below_edit = Some(edit_end.row() + 1);
 8897            let above_cursor =
 8898                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8899            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8900
 8901            // Place the edit popover adjacent to the edit if there is a location
 8902            // available that is onscreen and does not obscure the cursor. Otherwise,
 8903            // place it adjacent to the cursor.
 8904            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8905                .into_iter()
 8906                .flatten()
 8907                .find(|&start_row| {
 8908                    let end_row = start_row + line_count as u32;
 8909                    visible_row_range.contains(&start_row)
 8910                        && visible_row_range.contains(&end_row)
 8911                        && cursor_row.map_or(true, |cursor_row| {
 8912                            !((start_row..end_row).contains(&cursor_row))
 8913                        })
 8914                })?;
 8915
 8916            content_origin
 8917                + point(
 8918                    -scroll_pixel_position.x,
 8919                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8920                )
 8921        };
 8922
 8923        origin.x -= BORDER_WIDTH;
 8924
 8925        window.defer_draw(element, origin, 1);
 8926
 8927        // Do not return an element, since it will already be drawn due to defer_draw.
 8928        None
 8929    }
 8930
 8931    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8932        px(30.)
 8933    }
 8934
 8935    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8936        if self.read_only(cx) {
 8937            cx.theme().players().read_only()
 8938        } else {
 8939            self.style.as_ref().unwrap().local_player
 8940        }
 8941    }
 8942
 8943    fn render_edit_prediction_accept_keybind(
 8944        &self,
 8945        window: &mut Window,
 8946        cx: &App,
 8947    ) -> Option<AnyElement> {
 8948        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8949        let accept_keystroke = accept_binding.keystroke()?;
 8950
 8951        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8952
 8953        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8954            Color::Accent
 8955        } else {
 8956            Color::Muted
 8957        };
 8958
 8959        h_flex()
 8960            .px_0p5()
 8961            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8962            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8963            .text_size(TextSize::XSmall.rems(cx))
 8964            .child(h_flex().children(ui::render_modifiers(
 8965                &accept_keystroke.modifiers,
 8966                PlatformStyle::platform(),
 8967                Some(modifiers_color),
 8968                Some(IconSize::XSmall.rems().into()),
 8969                true,
 8970            )))
 8971            .when(is_platform_style_mac, |parent| {
 8972                parent.child(accept_keystroke.key.clone())
 8973            })
 8974            .when(!is_platform_style_mac, |parent| {
 8975                parent.child(
 8976                    Key::new(
 8977                        util::capitalize(&accept_keystroke.key),
 8978                        Some(Color::Default),
 8979                    )
 8980                    .size(Some(IconSize::XSmall.rems().into())),
 8981                )
 8982            })
 8983            .into_any()
 8984            .into()
 8985    }
 8986
 8987    fn render_edit_prediction_line_popover(
 8988        &self,
 8989        label: impl Into<SharedString>,
 8990        icon: Option<IconName>,
 8991        window: &mut Window,
 8992        cx: &App,
 8993    ) -> Option<Stateful<Div>> {
 8994        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8995
 8996        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8997        let has_keybind = keybind.is_some();
 8998
 8999        let result = h_flex()
 9000            .id("ep-line-popover")
 9001            .py_0p5()
 9002            .pl_1()
 9003            .pr(padding_right)
 9004            .gap_1()
 9005            .rounded_md()
 9006            .border_1()
 9007            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9008            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9009            .shadow_xs()
 9010            .when(!has_keybind, |el| {
 9011                let status_colors = cx.theme().status();
 9012
 9013                el.bg(status_colors.error_background)
 9014                    .border_color(status_colors.error.opacity(0.6))
 9015                    .pl_2()
 9016                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9017                    .cursor_default()
 9018                    .hoverable_tooltip(move |_window, cx| {
 9019                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9020                    })
 9021            })
 9022            .children(keybind)
 9023            .child(
 9024                Label::new(label)
 9025                    .size(LabelSize::Small)
 9026                    .when(!has_keybind, |el| {
 9027                        el.color(cx.theme().status().error.into()).strikethrough()
 9028                    }),
 9029            )
 9030            .when(!has_keybind, |el| {
 9031                el.child(
 9032                    h_flex().ml_1().child(
 9033                        Icon::new(IconName::Info)
 9034                            .size(IconSize::Small)
 9035                            .color(cx.theme().status().error.into()),
 9036                    ),
 9037                )
 9038            })
 9039            .when_some(icon, |element, icon| {
 9040                element.child(
 9041                    div()
 9042                        .mt(px(1.5))
 9043                        .child(Icon::new(icon).size(IconSize::Small)),
 9044                )
 9045            });
 9046
 9047        Some(result)
 9048    }
 9049
 9050    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9051        let accent_color = cx.theme().colors().text_accent;
 9052        let editor_bg_color = cx.theme().colors().editor_background;
 9053        editor_bg_color.blend(accent_color.opacity(0.1))
 9054    }
 9055
 9056    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9057        let accent_color = cx.theme().colors().text_accent;
 9058        let editor_bg_color = cx.theme().colors().editor_background;
 9059        editor_bg_color.blend(accent_color.opacity(0.6))
 9060    }
 9061
 9062    fn render_edit_prediction_cursor_popover(
 9063        &self,
 9064        min_width: Pixels,
 9065        max_width: Pixels,
 9066        cursor_point: Point,
 9067        style: &EditorStyle,
 9068        accept_keystroke: Option<&gpui::Keystroke>,
 9069        _window: &Window,
 9070        cx: &mut Context<Editor>,
 9071    ) -> Option<AnyElement> {
 9072        let provider = self.edit_prediction_provider.as_ref()?;
 9073
 9074        if provider.provider.needs_terms_acceptance(cx) {
 9075            return Some(
 9076                h_flex()
 9077                    .min_w(min_width)
 9078                    .flex_1()
 9079                    .px_2()
 9080                    .py_1()
 9081                    .gap_3()
 9082                    .elevation_2(cx)
 9083                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 9084                    .id("accept-terms")
 9085                    .cursor_pointer()
 9086                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 9087                    .on_click(cx.listener(|this, _event, window, cx| {
 9088                        cx.stop_propagation();
 9089                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 9090                        window.dispatch_action(
 9091                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 9092                            cx,
 9093                        );
 9094                    }))
 9095                    .child(
 9096                        h_flex()
 9097                            .flex_1()
 9098                            .gap_2()
 9099                            .child(Icon::new(IconName::ZedPredict))
 9100                            .child(Label::new("Accept Terms of Service"))
 9101                            .child(div().w_full())
 9102                            .child(
 9103                                Icon::new(IconName::ArrowUpRight)
 9104                                    .color(Color::Muted)
 9105                                    .size(IconSize::Small),
 9106                            )
 9107                            .into_any_element(),
 9108                    )
 9109                    .into_any(),
 9110            );
 9111        }
 9112
 9113        let is_refreshing = provider.provider.is_refreshing(cx);
 9114
 9115        fn pending_completion_container() -> Div {
 9116            h_flex()
 9117                .h_full()
 9118                .flex_1()
 9119                .gap_2()
 9120                .child(Icon::new(IconName::ZedPredict))
 9121        }
 9122
 9123        let completion = match &self.active_inline_completion {
 9124            Some(prediction) => {
 9125                if !self.has_visible_completions_menu() {
 9126                    const RADIUS: Pixels = px(6.);
 9127                    const BORDER_WIDTH: Pixels = px(1.);
 9128
 9129                    return Some(
 9130                        h_flex()
 9131                            .elevation_2(cx)
 9132                            .border(BORDER_WIDTH)
 9133                            .border_color(cx.theme().colors().border)
 9134                            .when(accept_keystroke.is_none(), |el| {
 9135                                el.border_color(cx.theme().status().error)
 9136                            })
 9137                            .rounded(RADIUS)
 9138                            .rounded_tl(px(0.))
 9139                            .overflow_hidden()
 9140                            .child(div().px_1p5().child(match &prediction.completion {
 9141                                InlineCompletion::Move { target, snapshot } => {
 9142                                    use text::ToPoint as _;
 9143                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 9144                                    {
 9145                                        Icon::new(IconName::ZedPredictDown)
 9146                                    } else {
 9147                                        Icon::new(IconName::ZedPredictUp)
 9148                                    }
 9149                                }
 9150                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 9151                            }))
 9152                            .child(
 9153                                h_flex()
 9154                                    .gap_1()
 9155                                    .py_1()
 9156                                    .px_2()
 9157                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9158                                    .border_l_1()
 9159                                    .border_color(cx.theme().colors().border)
 9160                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9161                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9162                                        el.child(
 9163                                            Label::new("Hold")
 9164                                                .size(LabelSize::Small)
 9165                                                .when(accept_keystroke.is_none(), |el| {
 9166                                                    el.strikethrough()
 9167                                                })
 9168                                                .line_height_style(LineHeightStyle::UiLabel),
 9169                                        )
 9170                                    })
 9171                                    .id("edit_prediction_cursor_popover_keybind")
 9172                                    .when(accept_keystroke.is_none(), |el| {
 9173                                        let status_colors = cx.theme().status();
 9174
 9175                                        el.bg(status_colors.error_background)
 9176                                            .border_color(status_colors.error.opacity(0.6))
 9177                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9178                                            .cursor_default()
 9179                                            .hoverable_tooltip(move |_window, cx| {
 9180                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9181                                                    .into()
 9182                                            })
 9183                                    })
 9184                                    .when_some(
 9185                                        accept_keystroke.as_ref(),
 9186                                        |el, accept_keystroke| {
 9187                                            el.child(h_flex().children(ui::render_modifiers(
 9188                                                &accept_keystroke.modifiers,
 9189                                                PlatformStyle::platform(),
 9190                                                Some(Color::Default),
 9191                                                Some(IconSize::XSmall.rems().into()),
 9192                                                false,
 9193                                            )))
 9194                                        },
 9195                                    ),
 9196                            )
 9197                            .into_any(),
 9198                    );
 9199                }
 9200
 9201                self.render_edit_prediction_cursor_popover_preview(
 9202                    prediction,
 9203                    cursor_point,
 9204                    style,
 9205                    cx,
 9206                )?
 9207            }
 9208
 9209            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 9210                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9211                    stale_completion,
 9212                    cursor_point,
 9213                    style,
 9214                    cx,
 9215                )?,
 9216
 9217                None => {
 9218                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 9219                }
 9220            },
 9221
 9222            None => pending_completion_container().child(Label::new("No Prediction")),
 9223        };
 9224
 9225        let completion = if is_refreshing {
 9226            completion
 9227                .with_animation(
 9228                    "loading-completion",
 9229                    Animation::new(Duration::from_secs(2))
 9230                        .repeat()
 9231                        .with_easing(pulsating_between(0.4, 0.8)),
 9232                    |label, delta| label.opacity(delta),
 9233                )
 9234                .into_any_element()
 9235        } else {
 9236            completion.into_any_element()
 9237        };
 9238
 9239        let has_completion = self.active_inline_completion.is_some();
 9240
 9241        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9242        Some(
 9243            h_flex()
 9244                .min_w(min_width)
 9245                .max_w(max_width)
 9246                .flex_1()
 9247                .elevation_2(cx)
 9248                .border_color(cx.theme().colors().border)
 9249                .child(
 9250                    div()
 9251                        .flex_1()
 9252                        .py_1()
 9253                        .px_2()
 9254                        .overflow_hidden()
 9255                        .child(completion),
 9256                )
 9257                .when_some(accept_keystroke, |el, accept_keystroke| {
 9258                    if !accept_keystroke.modifiers.modified() {
 9259                        return el;
 9260                    }
 9261
 9262                    el.child(
 9263                        h_flex()
 9264                            .h_full()
 9265                            .border_l_1()
 9266                            .rounded_r_lg()
 9267                            .border_color(cx.theme().colors().border)
 9268                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9269                            .gap_1()
 9270                            .py_1()
 9271                            .px_2()
 9272                            .child(
 9273                                h_flex()
 9274                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9275                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9276                                    .child(h_flex().children(ui::render_modifiers(
 9277                                        &accept_keystroke.modifiers,
 9278                                        PlatformStyle::platform(),
 9279                                        Some(if !has_completion {
 9280                                            Color::Muted
 9281                                        } else {
 9282                                            Color::Default
 9283                                        }),
 9284                                        None,
 9285                                        false,
 9286                                    ))),
 9287                            )
 9288                            .child(Label::new("Preview").into_any_element())
 9289                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9290                    )
 9291                })
 9292                .into_any(),
 9293        )
 9294    }
 9295
 9296    fn render_edit_prediction_cursor_popover_preview(
 9297        &self,
 9298        completion: &InlineCompletionState,
 9299        cursor_point: Point,
 9300        style: &EditorStyle,
 9301        cx: &mut Context<Editor>,
 9302    ) -> Option<Div> {
 9303        use text::ToPoint as _;
 9304
 9305        fn render_relative_row_jump(
 9306            prefix: impl Into<String>,
 9307            current_row: u32,
 9308            target_row: u32,
 9309        ) -> Div {
 9310            let (row_diff, arrow) = if target_row < current_row {
 9311                (current_row - target_row, IconName::ArrowUp)
 9312            } else {
 9313                (target_row - current_row, IconName::ArrowDown)
 9314            };
 9315
 9316            h_flex()
 9317                .child(
 9318                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9319                        .color(Color::Muted)
 9320                        .size(LabelSize::Small),
 9321                )
 9322                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9323        }
 9324
 9325        match &completion.completion {
 9326            InlineCompletion::Move {
 9327                target, snapshot, ..
 9328            } => Some(
 9329                h_flex()
 9330                    .px_2()
 9331                    .gap_2()
 9332                    .flex_1()
 9333                    .child(
 9334                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9335                            Icon::new(IconName::ZedPredictDown)
 9336                        } else {
 9337                            Icon::new(IconName::ZedPredictUp)
 9338                        },
 9339                    )
 9340                    .child(Label::new("Jump to Edit")),
 9341            ),
 9342
 9343            InlineCompletion::Edit {
 9344                edits,
 9345                edit_preview,
 9346                snapshot,
 9347                display_mode: _,
 9348            } => {
 9349                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9350
 9351                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 9352                    &snapshot,
 9353                    &edits,
 9354                    edit_preview.as_ref()?,
 9355                    true,
 9356                    cx,
 9357                )
 9358                .first_line_preview();
 9359
 9360                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9361                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9362
 9363                let preview = h_flex()
 9364                    .gap_1()
 9365                    .min_w_16()
 9366                    .child(styled_text)
 9367                    .when(has_more_lines, |parent| parent.child(""));
 9368
 9369                let left = if first_edit_row != cursor_point.row {
 9370                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9371                        .into_any_element()
 9372                } else {
 9373                    Icon::new(IconName::ZedPredict).into_any_element()
 9374                };
 9375
 9376                Some(
 9377                    h_flex()
 9378                        .h_full()
 9379                        .flex_1()
 9380                        .gap_2()
 9381                        .pr_1()
 9382                        .overflow_x_hidden()
 9383                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9384                        .child(left)
 9385                        .child(preview),
 9386                )
 9387            }
 9388        }
 9389    }
 9390
 9391    pub fn render_context_menu(
 9392        &self,
 9393        style: &EditorStyle,
 9394        max_height_in_lines: u32,
 9395        window: &mut Window,
 9396        cx: &mut Context<Editor>,
 9397    ) -> Option<AnyElement> {
 9398        let menu = self.context_menu.borrow();
 9399        let menu = menu.as_ref()?;
 9400        if !menu.visible() {
 9401            return None;
 9402        };
 9403        Some(menu.render(style, max_height_in_lines, window, cx))
 9404    }
 9405
 9406    fn render_context_menu_aside(
 9407        &mut self,
 9408        max_size: Size<Pixels>,
 9409        window: &mut Window,
 9410        cx: &mut Context<Editor>,
 9411    ) -> Option<AnyElement> {
 9412        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9413            if menu.visible() {
 9414                menu.render_aside(max_size, window, cx)
 9415            } else {
 9416                None
 9417            }
 9418        })
 9419    }
 9420
 9421    fn hide_context_menu(
 9422        &mut self,
 9423        window: &mut Window,
 9424        cx: &mut Context<Self>,
 9425    ) -> Option<CodeContextMenu> {
 9426        cx.notify();
 9427        self.completion_tasks.clear();
 9428        let context_menu = self.context_menu.borrow_mut().take();
 9429        self.stale_inline_completion_in_menu.take();
 9430        self.update_visible_inline_completion(window, cx);
 9431        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9432            if let Some(completion_provider) = &self.completion_provider {
 9433                completion_provider.selection_changed(None, window, cx);
 9434            }
 9435        }
 9436        context_menu
 9437    }
 9438
 9439    fn show_snippet_choices(
 9440        &mut self,
 9441        choices: &Vec<String>,
 9442        selection: Range<Anchor>,
 9443        cx: &mut Context<Self>,
 9444    ) {
 9445        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9446            (Some(a), Some(b)) if a == b => a,
 9447            _ => {
 9448                log::error!("expected anchor range to have matching buffer IDs");
 9449                return;
 9450            }
 9451        };
 9452        let multi_buffer = self.buffer().read(cx);
 9453        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9454            return;
 9455        };
 9456
 9457        let id = post_inc(&mut self.next_completion_id);
 9458        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9459        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9460            CompletionsMenu::new_snippet_choices(
 9461                id,
 9462                true,
 9463                choices,
 9464                selection,
 9465                buffer,
 9466                snippet_sort_order,
 9467            ),
 9468        ));
 9469    }
 9470
 9471    pub fn insert_snippet(
 9472        &mut self,
 9473        insertion_ranges: &[Range<usize>],
 9474        snippet: Snippet,
 9475        window: &mut Window,
 9476        cx: &mut Context<Self>,
 9477    ) -> Result<()> {
 9478        struct Tabstop<T> {
 9479            is_end_tabstop: bool,
 9480            ranges: Vec<Range<T>>,
 9481            choices: Option<Vec<String>>,
 9482        }
 9483
 9484        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9485            let snippet_text: Arc<str> = snippet.text.clone().into();
 9486            let edits = insertion_ranges
 9487                .iter()
 9488                .cloned()
 9489                .map(|range| (range, snippet_text.clone()));
 9490            let autoindent_mode = AutoindentMode::Block {
 9491                original_indent_columns: Vec::new(),
 9492            };
 9493            buffer.edit(edits, Some(autoindent_mode), cx);
 9494
 9495            let snapshot = &*buffer.read(cx);
 9496            let snippet = &snippet;
 9497            snippet
 9498                .tabstops
 9499                .iter()
 9500                .map(|tabstop| {
 9501                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9502                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9503                    });
 9504                    let mut tabstop_ranges = tabstop
 9505                        .ranges
 9506                        .iter()
 9507                        .flat_map(|tabstop_range| {
 9508                            let mut delta = 0_isize;
 9509                            insertion_ranges.iter().map(move |insertion_range| {
 9510                                let insertion_start = insertion_range.start as isize + delta;
 9511                                delta +=
 9512                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9513
 9514                                let start = ((insertion_start + tabstop_range.start) as usize)
 9515                                    .min(snapshot.len());
 9516                                let end = ((insertion_start + tabstop_range.end) as usize)
 9517                                    .min(snapshot.len());
 9518                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9519                            })
 9520                        })
 9521                        .collect::<Vec<_>>();
 9522                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9523
 9524                    Tabstop {
 9525                        is_end_tabstop,
 9526                        ranges: tabstop_ranges,
 9527                        choices: tabstop.choices.clone(),
 9528                    }
 9529                })
 9530                .collect::<Vec<_>>()
 9531        });
 9532        if let Some(tabstop) = tabstops.first() {
 9533            self.change_selections(Default::default(), window, cx, |s| {
 9534                // Reverse order so that the first range is the newest created selection.
 9535                // Completions will use it and autoscroll will prioritize it.
 9536                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9537            });
 9538
 9539            if let Some(choices) = &tabstop.choices {
 9540                if let Some(selection) = tabstop.ranges.first() {
 9541                    self.show_snippet_choices(choices, selection.clone(), cx)
 9542                }
 9543            }
 9544
 9545            // If we're already at the last tabstop and it's at the end of the snippet,
 9546            // we're done, we don't need to keep the state around.
 9547            if !tabstop.is_end_tabstop {
 9548                let choices = tabstops
 9549                    .iter()
 9550                    .map(|tabstop| tabstop.choices.clone())
 9551                    .collect();
 9552
 9553                let ranges = tabstops
 9554                    .into_iter()
 9555                    .map(|tabstop| tabstop.ranges)
 9556                    .collect::<Vec<_>>();
 9557
 9558                self.snippet_stack.push(SnippetState {
 9559                    active_index: 0,
 9560                    ranges,
 9561                    choices,
 9562                });
 9563            }
 9564
 9565            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9566            if self.autoclose_regions.is_empty() {
 9567                let snapshot = self.buffer.read(cx).snapshot(cx);
 9568                let mut all_selections = self.selections.all::<Point>(cx);
 9569                for selection in &mut all_selections {
 9570                    let selection_head = selection.head();
 9571                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9572                        continue;
 9573                    };
 9574
 9575                    let mut bracket_pair = None;
 9576                    let max_lookup_length = scope
 9577                        .brackets()
 9578                        .map(|(pair, _)| {
 9579                            pair.start
 9580                                .as_str()
 9581                                .chars()
 9582                                .count()
 9583                                .max(pair.end.as_str().chars().count())
 9584                        })
 9585                        .max();
 9586                    if let Some(max_lookup_length) = max_lookup_length {
 9587                        let next_text = snapshot
 9588                            .chars_at(selection_head)
 9589                            .take(max_lookup_length)
 9590                            .collect::<String>();
 9591                        let prev_text = snapshot
 9592                            .reversed_chars_at(selection_head)
 9593                            .take(max_lookup_length)
 9594                            .collect::<String>();
 9595
 9596                        for (pair, enabled) in scope.brackets() {
 9597                            if enabled
 9598                                && pair.close
 9599                                && prev_text.starts_with(pair.start.as_str())
 9600                                && next_text.starts_with(pair.end.as_str())
 9601                            {
 9602                                bracket_pair = Some(pair.clone());
 9603                                break;
 9604                            }
 9605                        }
 9606                    }
 9607
 9608                    if let Some(pair) = bracket_pair {
 9609                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9610                        let autoclose_enabled =
 9611                            self.use_autoclose && snapshot_settings.use_autoclose;
 9612                        if autoclose_enabled {
 9613                            let start = snapshot.anchor_after(selection_head);
 9614                            let end = snapshot.anchor_after(selection_head);
 9615                            self.autoclose_regions.push(AutocloseRegion {
 9616                                selection_id: selection.id,
 9617                                range: start..end,
 9618                                pair,
 9619                            });
 9620                        }
 9621                    }
 9622                }
 9623            }
 9624        }
 9625        Ok(())
 9626    }
 9627
 9628    pub fn move_to_next_snippet_tabstop(
 9629        &mut self,
 9630        window: &mut Window,
 9631        cx: &mut Context<Self>,
 9632    ) -> bool {
 9633        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9634    }
 9635
 9636    pub fn move_to_prev_snippet_tabstop(
 9637        &mut self,
 9638        window: &mut Window,
 9639        cx: &mut Context<Self>,
 9640    ) -> bool {
 9641        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9642    }
 9643
 9644    pub fn move_to_snippet_tabstop(
 9645        &mut self,
 9646        bias: Bias,
 9647        window: &mut Window,
 9648        cx: &mut Context<Self>,
 9649    ) -> bool {
 9650        if let Some(mut snippet) = self.snippet_stack.pop() {
 9651            match bias {
 9652                Bias::Left => {
 9653                    if snippet.active_index > 0 {
 9654                        snippet.active_index -= 1;
 9655                    } else {
 9656                        self.snippet_stack.push(snippet);
 9657                        return false;
 9658                    }
 9659                }
 9660                Bias::Right => {
 9661                    if snippet.active_index + 1 < snippet.ranges.len() {
 9662                        snippet.active_index += 1;
 9663                    } else {
 9664                        self.snippet_stack.push(snippet);
 9665                        return false;
 9666                    }
 9667                }
 9668            }
 9669            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9670                self.change_selections(Default::default(), window, cx, |s| {
 9671                    // Reverse order so that the first range is the newest created selection.
 9672                    // Completions will use it and autoscroll will prioritize it.
 9673                    s.select_ranges(current_ranges.iter().rev().cloned())
 9674                });
 9675
 9676                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9677                    if let Some(selection) = current_ranges.first() {
 9678                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9679                    }
 9680                }
 9681
 9682                // If snippet state is not at the last tabstop, push it back on the stack
 9683                if snippet.active_index + 1 < snippet.ranges.len() {
 9684                    self.snippet_stack.push(snippet);
 9685                }
 9686                return true;
 9687            }
 9688        }
 9689
 9690        false
 9691    }
 9692
 9693    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9694        self.transact(window, cx, |this, window, cx| {
 9695            this.select_all(&SelectAll, window, cx);
 9696            this.insert("", window, cx);
 9697        });
 9698    }
 9699
 9700    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9701        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9702        self.transact(window, cx, |this, window, cx| {
 9703            this.select_autoclose_pair(window, cx);
 9704            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9705            if !this.linked_edit_ranges.is_empty() {
 9706                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9707                let snapshot = this.buffer.read(cx).snapshot(cx);
 9708
 9709                for selection in selections.iter() {
 9710                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9711                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9712                    if selection_start.buffer_id != selection_end.buffer_id {
 9713                        continue;
 9714                    }
 9715                    if let Some(ranges) =
 9716                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9717                    {
 9718                        for (buffer, entries) in ranges {
 9719                            linked_ranges.entry(buffer).or_default().extend(entries);
 9720                        }
 9721                    }
 9722                }
 9723            }
 9724
 9725            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9726            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9727            for selection in &mut selections {
 9728                if selection.is_empty() {
 9729                    let old_head = selection.head();
 9730                    let mut new_head =
 9731                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9732                            .to_point(&display_map);
 9733                    if let Some((buffer, line_buffer_range)) = display_map
 9734                        .buffer_snapshot
 9735                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9736                    {
 9737                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9738                        let indent_len = match indent_size.kind {
 9739                            IndentKind::Space => {
 9740                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9741                            }
 9742                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9743                        };
 9744                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9745                            let indent_len = indent_len.get();
 9746                            new_head = cmp::min(
 9747                                new_head,
 9748                                MultiBufferPoint::new(
 9749                                    old_head.row,
 9750                                    ((old_head.column - 1) / indent_len) * indent_len,
 9751                                ),
 9752                            );
 9753                        }
 9754                    }
 9755
 9756                    selection.set_head(new_head, SelectionGoal::None);
 9757                }
 9758            }
 9759
 9760            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9761            this.insert("", window, cx);
 9762            let empty_str: Arc<str> = Arc::from("");
 9763            for (buffer, edits) in linked_ranges {
 9764                let snapshot = buffer.read(cx).snapshot();
 9765                use text::ToPoint as TP;
 9766
 9767                let edits = edits
 9768                    .into_iter()
 9769                    .map(|range| {
 9770                        let end_point = TP::to_point(&range.end, &snapshot);
 9771                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9772
 9773                        if end_point == start_point {
 9774                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9775                                .saturating_sub(1);
 9776                            start_point =
 9777                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9778                        };
 9779
 9780                        (start_point..end_point, empty_str.clone())
 9781                    })
 9782                    .sorted_by_key(|(range, _)| range.start)
 9783                    .collect::<Vec<_>>();
 9784                buffer.update(cx, |this, cx| {
 9785                    this.edit(edits, None, cx);
 9786                })
 9787            }
 9788            this.refresh_inline_completion(true, false, window, cx);
 9789            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9790        });
 9791    }
 9792
 9793    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9794        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9795        self.transact(window, cx, |this, window, cx| {
 9796            this.change_selections(Default::default(), window, cx, |s| {
 9797                s.move_with(|map, selection| {
 9798                    if selection.is_empty() {
 9799                        let cursor = movement::right(map, selection.head());
 9800                        selection.end = cursor;
 9801                        selection.reversed = true;
 9802                        selection.goal = SelectionGoal::None;
 9803                    }
 9804                })
 9805            });
 9806            this.insert("", window, cx);
 9807            this.refresh_inline_completion(true, false, window, cx);
 9808        });
 9809    }
 9810
 9811    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9812        if self.mode.is_single_line() {
 9813            cx.propagate();
 9814            return;
 9815        }
 9816
 9817        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9818        if self.move_to_prev_snippet_tabstop(window, cx) {
 9819            return;
 9820        }
 9821        self.outdent(&Outdent, window, cx);
 9822    }
 9823
 9824    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9825        if self.mode.is_single_line() {
 9826            cx.propagate();
 9827            return;
 9828        }
 9829
 9830        if self.move_to_next_snippet_tabstop(window, cx) {
 9831            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9832            return;
 9833        }
 9834        if self.read_only(cx) {
 9835            return;
 9836        }
 9837        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9838        let mut selections = self.selections.all_adjusted(cx);
 9839        let buffer = self.buffer.read(cx);
 9840        let snapshot = buffer.snapshot(cx);
 9841        let rows_iter = selections.iter().map(|s| s.head().row);
 9842        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9843
 9844        let has_some_cursor_in_whitespace = selections
 9845            .iter()
 9846            .filter(|selection| selection.is_empty())
 9847            .any(|selection| {
 9848                let cursor = selection.head();
 9849                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9850                cursor.column < current_indent.len
 9851            });
 9852
 9853        let mut edits = Vec::new();
 9854        let mut prev_edited_row = 0;
 9855        let mut row_delta = 0;
 9856        for selection in &mut selections {
 9857            if selection.start.row != prev_edited_row {
 9858                row_delta = 0;
 9859            }
 9860            prev_edited_row = selection.end.row;
 9861
 9862            // If the selection is non-empty, then increase the indentation of the selected lines.
 9863            if !selection.is_empty() {
 9864                row_delta =
 9865                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9866                continue;
 9867            }
 9868
 9869            let cursor = selection.head();
 9870            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9871            if let Some(suggested_indent) =
 9872                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9873            {
 9874                // Don't do anything if already at suggested indent
 9875                // and there is any other cursor which is not
 9876                if has_some_cursor_in_whitespace
 9877                    && cursor.column == current_indent.len
 9878                    && current_indent.len == suggested_indent.len
 9879                {
 9880                    continue;
 9881                }
 9882
 9883                // Adjust line and move cursor to suggested indent
 9884                // if cursor is not at suggested indent
 9885                if cursor.column < suggested_indent.len
 9886                    && cursor.column <= current_indent.len
 9887                    && current_indent.len <= suggested_indent.len
 9888                {
 9889                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9890                    selection.end = selection.start;
 9891                    if row_delta == 0 {
 9892                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9893                            cursor.row,
 9894                            current_indent,
 9895                            suggested_indent,
 9896                        ));
 9897                        row_delta = suggested_indent.len - current_indent.len;
 9898                    }
 9899                    continue;
 9900                }
 9901
 9902                // If current indent is more than suggested indent
 9903                // only move cursor to current indent and skip indent
 9904                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9905                    selection.start = Point::new(cursor.row, current_indent.len);
 9906                    selection.end = selection.start;
 9907                    continue;
 9908                }
 9909            }
 9910
 9911            // Otherwise, insert a hard or soft tab.
 9912            let settings = buffer.language_settings_at(cursor, cx);
 9913            let tab_size = if settings.hard_tabs {
 9914                IndentSize::tab()
 9915            } else {
 9916                let tab_size = settings.tab_size.get();
 9917                let indent_remainder = snapshot
 9918                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9919                    .flat_map(str::chars)
 9920                    .fold(row_delta % tab_size, |counter: u32, c| {
 9921                        if c == '\t' {
 9922                            0
 9923                        } else {
 9924                            (counter + 1) % tab_size
 9925                        }
 9926                    });
 9927
 9928                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9929                IndentSize::spaces(chars_to_next_tab_stop)
 9930            };
 9931            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9932            selection.end = selection.start;
 9933            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9934            row_delta += tab_size.len;
 9935        }
 9936
 9937        self.transact(window, cx, |this, window, cx| {
 9938            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9939            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9940            this.refresh_inline_completion(true, false, window, cx);
 9941        });
 9942    }
 9943
 9944    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9945        if self.read_only(cx) {
 9946            return;
 9947        }
 9948        if self.mode.is_single_line() {
 9949            cx.propagate();
 9950            return;
 9951        }
 9952
 9953        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9954        let mut selections = self.selections.all::<Point>(cx);
 9955        let mut prev_edited_row = 0;
 9956        let mut row_delta = 0;
 9957        let mut edits = Vec::new();
 9958        let buffer = self.buffer.read(cx);
 9959        let snapshot = buffer.snapshot(cx);
 9960        for selection in &mut selections {
 9961            if selection.start.row != prev_edited_row {
 9962                row_delta = 0;
 9963            }
 9964            prev_edited_row = selection.end.row;
 9965
 9966            row_delta =
 9967                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9968        }
 9969
 9970        self.transact(window, cx, |this, window, cx| {
 9971            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9972            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9973        });
 9974    }
 9975
 9976    fn indent_selection(
 9977        buffer: &MultiBuffer,
 9978        snapshot: &MultiBufferSnapshot,
 9979        selection: &mut Selection<Point>,
 9980        edits: &mut Vec<(Range<Point>, String)>,
 9981        delta_for_start_row: u32,
 9982        cx: &App,
 9983    ) -> u32 {
 9984        let settings = buffer.language_settings_at(selection.start, cx);
 9985        let tab_size = settings.tab_size.get();
 9986        let indent_kind = if settings.hard_tabs {
 9987            IndentKind::Tab
 9988        } else {
 9989            IndentKind::Space
 9990        };
 9991        let mut start_row = selection.start.row;
 9992        let mut end_row = selection.end.row + 1;
 9993
 9994        // If a selection ends at the beginning of a line, don't indent
 9995        // that last line.
 9996        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9997            end_row -= 1;
 9998        }
 9999
10000        // Avoid re-indenting a row that has already been indented by a
10001        // previous selection, but still update this selection's column
10002        // to reflect that indentation.
10003        if delta_for_start_row > 0 {
10004            start_row += 1;
10005            selection.start.column += delta_for_start_row;
10006            if selection.end.row == selection.start.row {
10007                selection.end.column += delta_for_start_row;
10008            }
10009        }
10010
10011        let mut delta_for_end_row = 0;
10012        let has_multiple_rows = start_row + 1 != end_row;
10013        for row in start_row..end_row {
10014            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10015            let indent_delta = match (current_indent.kind, indent_kind) {
10016                (IndentKind::Space, IndentKind::Space) => {
10017                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10018                    IndentSize::spaces(columns_to_next_tab_stop)
10019                }
10020                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10021                (_, IndentKind::Tab) => IndentSize::tab(),
10022            };
10023
10024            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10025                0
10026            } else {
10027                selection.start.column
10028            };
10029            let row_start = Point::new(row, start);
10030            edits.push((
10031                row_start..row_start,
10032                indent_delta.chars().collect::<String>(),
10033            ));
10034
10035            // Update this selection's endpoints to reflect the indentation.
10036            if row == selection.start.row {
10037                selection.start.column += indent_delta.len;
10038            }
10039            if row == selection.end.row {
10040                selection.end.column += indent_delta.len;
10041                delta_for_end_row = indent_delta.len;
10042            }
10043        }
10044
10045        if selection.start.row == selection.end.row {
10046            delta_for_start_row + delta_for_end_row
10047        } else {
10048            delta_for_end_row
10049        }
10050    }
10051
10052    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10053        if self.read_only(cx) {
10054            return;
10055        }
10056        if self.mode.is_single_line() {
10057            cx.propagate();
10058            return;
10059        }
10060
10061        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10062        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10063        let selections = self.selections.all::<Point>(cx);
10064        let mut deletion_ranges = Vec::new();
10065        let mut last_outdent = None;
10066        {
10067            let buffer = self.buffer.read(cx);
10068            let snapshot = buffer.snapshot(cx);
10069            for selection in &selections {
10070                let settings = buffer.language_settings_at(selection.start, cx);
10071                let tab_size = settings.tab_size.get();
10072                let mut rows = selection.spanned_rows(false, &display_map);
10073
10074                // Avoid re-outdenting a row that has already been outdented by a
10075                // previous selection.
10076                if let Some(last_row) = last_outdent {
10077                    if last_row == rows.start {
10078                        rows.start = rows.start.next_row();
10079                    }
10080                }
10081                let has_multiple_rows = rows.len() > 1;
10082                for row in rows.iter_rows() {
10083                    let indent_size = snapshot.indent_size_for_line(row);
10084                    if indent_size.len > 0 {
10085                        let deletion_len = match indent_size.kind {
10086                            IndentKind::Space => {
10087                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10088                                if columns_to_prev_tab_stop == 0 {
10089                                    tab_size
10090                                } else {
10091                                    columns_to_prev_tab_stop
10092                                }
10093                            }
10094                            IndentKind::Tab => 1,
10095                        };
10096                        let start = if has_multiple_rows
10097                            || deletion_len > selection.start.column
10098                            || indent_size.len < selection.start.column
10099                        {
10100                            0
10101                        } else {
10102                            selection.start.column - deletion_len
10103                        };
10104                        deletion_ranges.push(
10105                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10106                        );
10107                        last_outdent = Some(row);
10108                    }
10109                }
10110            }
10111        }
10112
10113        self.transact(window, cx, |this, window, cx| {
10114            this.buffer.update(cx, |buffer, cx| {
10115                let empty_str: Arc<str> = Arc::default();
10116                buffer.edit(
10117                    deletion_ranges
10118                        .into_iter()
10119                        .map(|range| (range, empty_str.clone())),
10120                    None,
10121                    cx,
10122                );
10123            });
10124            let selections = this.selections.all::<usize>(cx);
10125            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10126        });
10127    }
10128
10129    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10130        if self.read_only(cx) {
10131            return;
10132        }
10133        if self.mode.is_single_line() {
10134            cx.propagate();
10135            return;
10136        }
10137
10138        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10139        let selections = self
10140            .selections
10141            .all::<usize>(cx)
10142            .into_iter()
10143            .map(|s| s.range());
10144
10145        self.transact(window, cx, |this, window, cx| {
10146            this.buffer.update(cx, |buffer, cx| {
10147                buffer.autoindent_ranges(selections, cx);
10148            });
10149            let selections = this.selections.all::<usize>(cx);
10150            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10151        });
10152    }
10153
10154    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10155        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10156        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10157        let selections = self.selections.all::<Point>(cx);
10158
10159        let mut new_cursors = Vec::new();
10160        let mut edit_ranges = Vec::new();
10161        let mut selections = selections.iter().peekable();
10162        while let Some(selection) = selections.next() {
10163            let mut rows = selection.spanned_rows(false, &display_map);
10164            let goal_display_column = selection.head().to_display_point(&display_map).column();
10165
10166            // Accumulate contiguous regions of rows that we want to delete.
10167            while let Some(next_selection) = selections.peek() {
10168                let next_rows = next_selection.spanned_rows(false, &display_map);
10169                if next_rows.start <= rows.end {
10170                    rows.end = next_rows.end;
10171                    selections.next().unwrap();
10172                } else {
10173                    break;
10174                }
10175            }
10176
10177            let buffer = &display_map.buffer_snapshot;
10178            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10179            let edit_end;
10180            let cursor_buffer_row;
10181            if buffer.max_point().row >= rows.end.0 {
10182                // If there's a line after the range, delete the \n from the end of the row range
10183                // and position the cursor on the next line.
10184                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10185                cursor_buffer_row = rows.end;
10186            } else {
10187                // If there isn't a line after the range, delete the \n from the line before the
10188                // start of the row range and position the cursor there.
10189                edit_start = edit_start.saturating_sub(1);
10190                edit_end = buffer.len();
10191                cursor_buffer_row = rows.start.previous_row();
10192            }
10193
10194            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10195            *cursor.column_mut() =
10196                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10197
10198            new_cursors.push((
10199                selection.id,
10200                buffer.anchor_after(cursor.to_point(&display_map)),
10201            ));
10202            edit_ranges.push(edit_start..edit_end);
10203        }
10204
10205        self.transact(window, cx, |this, window, cx| {
10206            let buffer = this.buffer.update(cx, |buffer, cx| {
10207                let empty_str: Arc<str> = Arc::default();
10208                buffer.edit(
10209                    edit_ranges
10210                        .into_iter()
10211                        .map(|range| (range, empty_str.clone())),
10212                    None,
10213                    cx,
10214                );
10215                buffer.snapshot(cx)
10216            });
10217            let new_selections = new_cursors
10218                .into_iter()
10219                .map(|(id, cursor)| {
10220                    let cursor = cursor.to_point(&buffer);
10221                    Selection {
10222                        id,
10223                        start: cursor,
10224                        end: cursor,
10225                        reversed: false,
10226                        goal: SelectionGoal::None,
10227                    }
10228                })
10229                .collect();
10230
10231            this.change_selections(Default::default(), window, cx, |s| {
10232                s.select(new_selections);
10233            });
10234        });
10235    }
10236
10237    pub fn join_lines_impl(
10238        &mut self,
10239        insert_whitespace: bool,
10240        window: &mut Window,
10241        cx: &mut Context<Self>,
10242    ) {
10243        if self.read_only(cx) {
10244            return;
10245        }
10246        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10247        for selection in self.selections.all::<Point>(cx) {
10248            let start = MultiBufferRow(selection.start.row);
10249            // Treat single line selections as if they include the next line. Otherwise this action
10250            // would do nothing for single line selections individual cursors.
10251            let end = if selection.start.row == selection.end.row {
10252                MultiBufferRow(selection.start.row + 1)
10253            } else {
10254                MultiBufferRow(selection.end.row)
10255            };
10256
10257            if let Some(last_row_range) = row_ranges.last_mut() {
10258                if start <= last_row_range.end {
10259                    last_row_range.end = end;
10260                    continue;
10261                }
10262            }
10263            row_ranges.push(start..end);
10264        }
10265
10266        let snapshot = self.buffer.read(cx).snapshot(cx);
10267        let mut cursor_positions = Vec::new();
10268        for row_range in &row_ranges {
10269            let anchor = snapshot.anchor_before(Point::new(
10270                row_range.end.previous_row().0,
10271                snapshot.line_len(row_range.end.previous_row()),
10272            ));
10273            cursor_positions.push(anchor..anchor);
10274        }
10275
10276        self.transact(window, cx, |this, window, cx| {
10277            for row_range in row_ranges.into_iter().rev() {
10278                for row in row_range.iter_rows().rev() {
10279                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10280                    let next_line_row = row.next_row();
10281                    let indent = snapshot.indent_size_for_line(next_line_row);
10282                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10283
10284                    let replace =
10285                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10286                            " "
10287                        } else {
10288                            ""
10289                        };
10290
10291                    this.buffer.update(cx, |buffer, cx| {
10292                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10293                    });
10294                }
10295            }
10296
10297            this.change_selections(Default::default(), window, cx, |s| {
10298                s.select_anchor_ranges(cursor_positions)
10299            });
10300        });
10301    }
10302
10303    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10304        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10305        self.join_lines_impl(true, window, cx);
10306    }
10307
10308    pub fn sort_lines_case_sensitive(
10309        &mut self,
10310        _: &SortLinesCaseSensitive,
10311        window: &mut Window,
10312        cx: &mut Context<Self>,
10313    ) {
10314        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10315    }
10316
10317    pub fn sort_lines_by_length(
10318        &mut self,
10319        _: &SortLinesByLength,
10320        window: &mut Window,
10321        cx: &mut Context<Self>,
10322    ) {
10323        self.manipulate_immutable_lines(window, cx, |lines| {
10324            lines.sort_by_key(|&line| line.chars().count())
10325        })
10326    }
10327
10328    pub fn sort_lines_case_insensitive(
10329        &mut self,
10330        _: &SortLinesCaseInsensitive,
10331        window: &mut Window,
10332        cx: &mut Context<Self>,
10333    ) {
10334        self.manipulate_immutable_lines(window, cx, |lines| {
10335            lines.sort_by_key(|line| line.to_lowercase())
10336        })
10337    }
10338
10339    pub fn unique_lines_case_insensitive(
10340        &mut self,
10341        _: &UniqueLinesCaseInsensitive,
10342        window: &mut Window,
10343        cx: &mut Context<Self>,
10344    ) {
10345        self.manipulate_immutable_lines(window, cx, |lines| {
10346            let mut seen = HashSet::default();
10347            lines.retain(|line| seen.insert(line.to_lowercase()));
10348        })
10349    }
10350
10351    pub fn unique_lines_case_sensitive(
10352        &mut self,
10353        _: &UniqueLinesCaseSensitive,
10354        window: &mut Window,
10355        cx: &mut Context<Self>,
10356    ) {
10357        self.manipulate_immutable_lines(window, cx, |lines| {
10358            let mut seen = HashSet::default();
10359            lines.retain(|line| seen.insert(*line));
10360        })
10361    }
10362
10363    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10364        let Some(project) = self.project.clone() else {
10365            return;
10366        };
10367        self.reload(project, window, cx)
10368            .detach_and_notify_err(window, cx);
10369    }
10370
10371    pub fn restore_file(
10372        &mut self,
10373        _: &::git::RestoreFile,
10374        window: &mut Window,
10375        cx: &mut Context<Self>,
10376    ) {
10377        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10378        let mut buffer_ids = HashSet::default();
10379        let snapshot = self.buffer().read(cx).snapshot(cx);
10380        for selection in self.selections.all::<usize>(cx) {
10381            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10382        }
10383
10384        let buffer = self.buffer().read(cx);
10385        let ranges = buffer_ids
10386            .into_iter()
10387            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10388            .collect::<Vec<_>>();
10389
10390        self.restore_hunks_in_ranges(ranges, window, cx);
10391    }
10392
10393    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10394        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10395        let selections = self
10396            .selections
10397            .all(cx)
10398            .into_iter()
10399            .map(|s| s.range())
10400            .collect();
10401        self.restore_hunks_in_ranges(selections, window, cx);
10402    }
10403
10404    pub fn restore_hunks_in_ranges(
10405        &mut self,
10406        ranges: Vec<Range<Point>>,
10407        window: &mut Window,
10408        cx: &mut Context<Editor>,
10409    ) {
10410        let mut revert_changes = HashMap::default();
10411        let chunk_by = self
10412            .snapshot(window, cx)
10413            .hunks_for_ranges(ranges)
10414            .into_iter()
10415            .chunk_by(|hunk| hunk.buffer_id);
10416        for (buffer_id, hunks) in &chunk_by {
10417            let hunks = hunks.collect::<Vec<_>>();
10418            for hunk in &hunks {
10419                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10420            }
10421            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10422        }
10423        drop(chunk_by);
10424        if !revert_changes.is_empty() {
10425            self.transact(window, cx, |editor, window, cx| {
10426                editor.restore(revert_changes, window, cx);
10427            });
10428        }
10429    }
10430
10431    pub fn open_active_item_in_terminal(
10432        &mut self,
10433        _: &OpenInTerminal,
10434        window: &mut Window,
10435        cx: &mut Context<Self>,
10436    ) {
10437        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10438            let project_path = buffer.read(cx).project_path(cx)?;
10439            let project = self.project.as_ref()?.read(cx);
10440            let entry = project.entry_for_path(&project_path, cx)?;
10441            let parent = match &entry.canonical_path {
10442                Some(canonical_path) => canonical_path.to_path_buf(),
10443                None => project.absolute_path(&project_path, cx)?,
10444            }
10445            .parent()?
10446            .to_path_buf();
10447            Some(parent)
10448        }) {
10449            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10450        }
10451    }
10452
10453    fn set_breakpoint_context_menu(
10454        &mut self,
10455        display_row: DisplayRow,
10456        position: Option<Anchor>,
10457        clicked_point: gpui::Point<Pixels>,
10458        window: &mut Window,
10459        cx: &mut Context<Self>,
10460    ) {
10461        let source = self
10462            .buffer
10463            .read(cx)
10464            .snapshot(cx)
10465            .anchor_before(Point::new(display_row.0, 0u32));
10466
10467        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10468
10469        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10470            self,
10471            source,
10472            clicked_point,
10473            context_menu,
10474            window,
10475            cx,
10476        );
10477    }
10478
10479    fn add_edit_breakpoint_block(
10480        &mut self,
10481        anchor: Anchor,
10482        breakpoint: &Breakpoint,
10483        edit_action: BreakpointPromptEditAction,
10484        window: &mut Window,
10485        cx: &mut Context<Self>,
10486    ) {
10487        let weak_editor = cx.weak_entity();
10488        let bp_prompt = cx.new(|cx| {
10489            BreakpointPromptEditor::new(
10490                weak_editor,
10491                anchor,
10492                breakpoint.clone(),
10493                edit_action,
10494                window,
10495                cx,
10496            )
10497        });
10498
10499        let height = bp_prompt.update(cx, |this, cx| {
10500            this.prompt
10501                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10502        });
10503        let cloned_prompt = bp_prompt.clone();
10504        let blocks = vec![BlockProperties {
10505            style: BlockStyle::Sticky,
10506            placement: BlockPlacement::Above(anchor),
10507            height: Some(height),
10508            render: Arc::new(move |cx| {
10509                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10510                cloned_prompt.clone().into_any_element()
10511            }),
10512            priority: 0,
10513        }];
10514
10515        let focus_handle = bp_prompt.focus_handle(cx);
10516        window.focus(&focus_handle);
10517
10518        let block_ids = self.insert_blocks(blocks, None, cx);
10519        bp_prompt.update(cx, |prompt, _| {
10520            prompt.add_block_ids(block_ids);
10521        });
10522    }
10523
10524    pub(crate) fn breakpoint_at_row(
10525        &self,
10526        row: u32,
10527        window: &mut Window,
10528        cx: &mut Context<Self>,
10529    ) -> Option<(Anchor, Breakpoint)> {
10530        let snapshot = self.snapshot(window, cx);
10531        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10532
10533        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10534    }
10535
10536    pub(crate) fn breakpoint_at_anchor(
10537        &self,
10538        breakpoint_position: Anchor,
10539        snapshot: &EditorSnapshot,
10540        cx: &mut Context<Self>,
10541    ) -> Option<(Anchor, Breakpoint)> {
10542        let project = self.project.clone()?;
10543
10544        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10545            snapshot
10546                .buffer_snapshot
10547                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10548        })?;
10549
10550        let enclosing_excerpt = breakpoint_position.excerpt_id;
10551        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10552        let buffer_snapshot = buffer.read(cx).snapshot();
10553
10554        let row = buffer_snapshot
10555            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10556            .row;
10557
10558        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10559        let anchor_end = snapshot
10560            .buffer_snapshot
10561            .anchor_after(Point::new(row, line_len));
10562
10563        let bp = self
10564            .breakpoint_store
10565            .as_ref()?
10566            .read_with(cx, |breakpoint_store, cx| {
10567                breakpoint_store
10568                    .breakpoints(
10569                        &buffer,
10570                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10571                        &buffer_snapshot,
10572                        cx,
10573                    )
10574                    .next()
10575                    .and_then(|(bp, _)| {
10576                        let breakpoint_row = buffer_snapshot
10577                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10578                            .row;
10579
10580                        if breakpoint_row == row {
10581                            snapshot
10582                                .buffer_snapshot
10583                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10584                                .map(|position| (position, bp.bp.clone()))
10585                        } else {
10586                            None
10587                        }
10588                    })
10589            });
10590        bp
10591    }
10592
10593    pub fn edit_log_breakpoint(
10594        &mut self,
10595        _: &EditLogBreakpoint,
10596        window: &mut Window,
10597        cx: &mut Context<Self>,
10598    ) {
10599        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10600            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10601                message: None,
10602                state: BreakpointState::Enabled,
10603                condition: None,
10604                hit_condition: None,
10605            });
10606
10607            self.add_edit_breakpoint_block(
10608                anchor,
10609                &breakpoint,
10610                BreakpointPromptEditAction::Log,
10611                window,
10612                cx,
10613            );
10614        }
10615    }
10616
10617    fn breakpoints_at_cursors(
10618        &self,
10619        window: &mut Window,
10620        cx: &mut Context<Self>,
10621    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10622        let snapshot = self.snapshot(window, cx);
10623        let cursors = self
10624            .selections
10625            .disjoint_anchors()
10626            .into_iter()
10627            .map(|selection| {
10628                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10629
10630                let breakpoint_position = self
10631                    .breakpoint_at_row(cursor_position.row, window, cx)
10632                    .map(|bp| bp.0)
10633                    .unwrap_or_else(|| {
10634                        snapshot
10635                            .display_snapshot
10636                            .buffer_snapshot
10637                            .anchor_after(Point::new(cursor_position.row, 0))
10638                    });
10639
10640                let breakpoint = self
10641                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10642                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10643
10644                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10645            })
10646            // 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.
10647            .collect::<HashMap<Anchor, _>>();
10648
10649        cursors.into_iter().collect()
10650    }
10651
10652    pub fn enable_breakpoint(
10653        &mut self,
10654        _: &crate::actions::EnableBreakpoint,
10655        window: &mut Window,
10656        cx: &mut Context<Self>,
10657    ) {
10658        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10659            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10660                continue;
10661            };
10662            self.edit_breakpoint_at_anchor(
10663                anchor,
10664                breakpoint,
10665                BreakpointEditAction::InvertState,
10666                cx,
10667            );
10668        }
10669    }
10670
10671    pub fn disable_breakpoint(
10672        &mut self,
10673        _: &crate::actions::DisableBreakpoint,
10674        window: &mut Window,
10675        cx: &mut Context<Self>,
10676    ) {
10677        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10678            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10679                continue;
10680            };
10681            self.edit_breakpoint_at_anchor(
10682                anchor,
10683                breakpoint,
10684                BreakpointEditAction::InvertState,
10685                cx,
10686            );
10687        }
10688    }
10689
10690    pub fn toggle_breakpoint(
10691        &mut self,
10692        _: &crate::actions::ToggleBreakpoint,
10693        window: &mut Window,
10694        cx: &mut Context<Self>,
10695    ) {
10696        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10697            if let Some(breakpoint) = breakpoint {
10698                self.edit_breakpoint_at_anchor(
10699                    anchor,
10700                    breakpoint,
10701                    BreakpointEditAction::Toggle,
10702                    cx,
10703                );
10704            } else {
10705                self.edit_breakpoint_at_anchor(
10706                    anchor,
10707                    Breakpoint::new_standard(),
10708                    BreakpointEditAction::Toggle,
10709                    cx,
10710                );
10711            }
10712        }
10713    }
10714
10715    pub fn edit_breakpoint_at_anchor(
10716        &mut self,
10717        breakpoint_position: Anchor,
10718        breakpoint: Breakpoint,
10719        edit_action: BreakpointEditAction,
10720        cx: &mut Context<Self>,
10721    ) {
10722        let Some(breakpoint_store) = &self.breakpoint_store else {
10723            return;
10724        };
10725
10726        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10727            if breakpoint_position == Anchor::min() {
10728                self.buffer()
10729                    .read(cx)
10730                    .excerpt_buffer_ids()
10731                    .into_iter()
10732                    .next()
10733            } else {
10734                None
10735            }
10736        }) else {
10737            return;
10738        };
10739
10740        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10741            return;
10742        };
10743
10744        breakpoint_store.update(cx, |breakpoint_store, cx| {
10745            breakpoint_store.toggle_breakpoint(
10746                buffer,
10747                BreakpointWithPosition {
10748                    position: breakpoint_position.text_anchor,
10749                    bp: breakpoint,
10750                },
10751                edit_action,
10752                cx,
10753            );
10754        });
10755
10756        cx.notify();
10757    }
10758
10759    #[cfg(any(test, feature = "test-support"))]
10760    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10761        self.breakpoint_store.clone()
10762    }
10763
10764    pub fn prepare_restore_change(
10765        &self,
10766        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10767        hunk: &MultiBufferDiffHunk,
10768        cx: &mut App,
10769    ) -> Option<()> {
10770        if hunk.is_created_file() {
10771            return None;
10772        }
10773        let buffer = self.buffer.read(cx);
10774        let diff = buffer.diff_for(hunk.buffer_id)?;
10775        let buffer = buffer.buffer(hunk.buffer_id)?;
10776        let buffer = buffer.read(cx);
10777        let original_text = diff
10778            .read(cx)
10779            .base_text()
10780            .as_rope()
10781            .slice(hunk.diff_base_byte_range.clone());
10782        let buffer_snapshot = buffer.snapshot();
10783        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10784        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10785            probe
10786                .0
10787                .start
10788                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10789                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10790        }) {
10791            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10792            Some(())
10793        } else {
10794            None
10795        }
10796    }
10797
10798    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10799        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10800    }
10801
10802    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10803        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10804    }
10805
10806    fn manipulate_lines<M>(
10807        &mut self,
10808        window: &mut Window,
10809        cx: &mut Context<Self>,
10810        mut manipulate: M,
10811    ) where
10812        M: FnMut(&str) -> LineManipulationResult,
10813    {
10814        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10815
10816        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10817        let buffer = self.buffer.read(cx).snapshot(cx);
10818
10819        let mut edits = Vec::new();
10820
10821        let selections = self.selections.all::<Point>(cx);
10822        let mut selections = selections.iter().peekable();
10823        let mut contiguous_row_selections = Vec::new();
10824        let mut new_selections = Vec::new();
10825        let mut added_lines = 0;
10826        let mut removed_lines = 0;
10827
10828        while let Some(selection) = selections.next() {
10829            let (start_row, end_row) = consume_contiguous_rows(
10830                &mut contiguous_row_selections,
10831                selection,
10832                &display_map,
10833                &mut selections,
10834            );
10835
10836            let start_point = Point::new(start_row.0, 0);
10837            let end_point = Point::new(
10838                end_row.previous_row().0,
10839                buffer.line_len(end_row.previous_row()),
10840            );
10841            let text = buffer
10842                .text_for_range(start_point..end_point)
10843                .collect::<String>();
10844
10845            let LineManipulationResult {
10846                new_text,
10847                line_count_before,
10848                line_count_after,
10849            } = manipulate(&text);
10850
10851            edits.push((start_point..end_point, new_text));
10852
10853            // Selections must change based on added and removed line count
10854            let start_row =
10855                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10856            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10857            new_selections.push(Selection {
10858                id: selection.id,
10859                start: start_row,
10860                end: end_row,
10861                goal: SelectionGoal::None,
10862                reversed: selection.reversed,
10863            });
10864
10865            if line_count_after > line_count_before {
10866                added_lines += line_count_after - line_count_before;
10867            } else if line_count_before > line_count_after {
10868                removed_lines += line_count_before - line_count_after;
10869            }
10870        }
10871
10872        self.transact(window, cx, |this, window, cx| {
10873            let buffer = this.buffer.update(cx, |buffer, cx| {
10874                buffer.edit(edits, None, cx);
10875                buffer.snapshot(cx)
10876            });
10877
10878            // Recalculate offsets on newly edited buffer
10879            let new_selections = new_selections
10880                .iter()
10881                .map(|s| {
10882                    let start_point = Point::new(s.start.0, 0);
10883                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10884                    Selection {
10885                        id: s.id,
10886                        start: buffer.point_to_offset(start_point),
10887                        end: buffer.point_to_offset(end_point),
10888                        goal: s.goal,
10889                        reversed: s.reversed,
10890                    }
10891                })
10892                .collect();
10893
10894            this.change_selections(Default::default(), window, cx, |s| {
10895                s.select(new_selections);
10896            });
10897
10898            this.request_autoscroll(Autoscroll::fit(), cx);
10899        });
10900    }
10901
10902    fn manipulate_immutable_lines<Fn>(
10903        &mut self,
10904        window: &mut Window,
10905        cx: &mut Context<Self>,
10906        mut callback: Fn,
10907    ) where
10908        Fn: FnMut(&mut Vec<&str>),
10909    {
10910        self.manipulate_lines(window, cx, |text| {
10911            let mut lines: Vec<&str> = text.split('\n').collect();
10912            let line_count_before = lines.len();
10913
10914            callback(&mut lines);
10915
10916            LineManipulationResult {
10917                new_text: lines.join("\n"),
10918                line_count_before,
10919                line_count_after: lines.len(),
10920            }
10921        });
10922    }
10923
10924    fn manipulate_mutable_lines<Fn>(
10925        &mut self,
10926        window: &mut Window,
10927        cx: &mut Context<Self>,
10928        mut callback: Fn,
10929    ) where
10930        Fn: FnMut(&mut Vec<Cow<'_, str>>),
10931    {
10932        self.manipulate_lines(window, cx, |text| {
10933            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
10934            let line_count_before = lines.len();
10935
10936            callback(&mut lines);
10937
10938            LineManipulationResult {
10939                new_text: lines.join("\n"),
10940                line_count_before,
10941                line_count_after: lines.len(),
10942            }
10943        });
10944    }
10945
10946    pub fn convert_indentation_to_spaces(
10947        &mut self,
10948        _: &ConvertIndentationToSpaces,
10949        window: &mut Window,
10950        cx: &mut Context<Self>,
10951    ) {
10952        let settings = self.buffer.read(cx).language_settings(cx);
10953        let tab_size = settings.tab_size.get() as usize;
10954
10955        self.manipulate_mutable_lines(window, cx, |lines| {
10956            // Allocates a reasonably sized scratch buffer once for the whole loop
10957            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10958            // Avoids recomputing spaces that could be inserted many times
10959            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10960                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10961                .collect();
10962
10963            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10964                let mut chars = line.as_ref().chars();
10965                let mut col = 0;
10966                let mut changed = false;
10967
10968                while let Some(ch) = chars.next() {
10969                    match ch {
10970                        ' ' => {
10971                            reindented_line.push(' ');
10972                            col += 1;
10973                        }
10974                        '\t' => {
10975                            // \t are converted to spaces depending on the current column
10976                            let spaces_len = tab_size - (col % tab_size);
10977                            reindented_line.extend(&space_cache[spaces_len - 1]);
10978                            col += spaces_len;
10979                            changed = true;
10980                        }
10981                        _ => {
10982                            // If we dont append before break, the character is consumed
10983                            reindented_line.push(ch);
10984                            break;
10985                        }
10986                    }
10987                }
10988
10989                if !changed {
10990                    reindented_line.clear();
10991                    continue;
10992                }
10993                // Append the rest of the line and replace old reference with new one
10994                reindented_line.extend(chars);
10995                *line = Cow::Owned(reindented_line.clone());
10996                reindented_line.clear();
10997            }
10998        });
10999    }
11000
11001    pub fn convert_indentation_to_tabs(
11002        &mut self,
11003        _: &ConvertIndentationToTabs,
11004        window: &mut Window,
11005        cx: &mut Context<Self>,
11006    ) {
11007        let settings = self.buffer.read(cx).language_settings(cx);
11008        let tab_size = settings.tab_size.get() as usize;
11009
11010        self.manipulate_mutable_lines(window, cx, |lines| {
11011            // Allocates a reasonably sized buffer once for the whole loop
11012            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11013            // Avoids recomputing spaces that could be inserted many times
11014            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11015                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11016                .collect();
11017
11018            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11019                let mut chars = line.chars();
11020                let mut spaces_count = 0;
11021                let mut first_non_indent_char = None;
11022                let mut changed = false;
11023
11024                while let Some(ch) = chars.next() {
11025                    match ch {
11026                        ' ' => {
11027                            // Keep track of spaces. Append \t when we reach tab_size
11028                            spaces_count += 1;
11029                            changed = true;
11030                            if spaces_count == tab_size {
11031                                reindented_line.push('\t');
11032                                spaces_count = 0;
11033                            }
11034                        }
11035                        '\t' => {
11036                            reindented_line.push('\t');
11037                            spaces_count = 0;
11038                        }
11039                        _ => {
11040                            // Dont append it yet, we might have remaining spaces
11041                            first_non_indent_char = Some(ch);
11042                            break;
11043                        }
11044                    }
11045                }
11046
11047                if !changed {
11048                    reindented_line.clear();
11049                    continue;
11050                }
11051                // Remaining spaces that didn't make a full tab stop
11052                if spaces_count > 0 {
11053                    reindented_line.extend(&space_cache[spaces_count - 1]);
11054                }
11055                // If we consume an extra character that was not indentation, add it back
11056                if let Some(extra_char) = first_non_indent_char {
11057                    reindented_line.push(extra_char);
11058                }
11059                // Append the rest of the line and replace old reference with new one
11060                reindented_line.extend(chars);
11061                *line = Cow::Owned(reindented_line.clone());
11062                reindented_line.clear();
11063            }
11064        });
11065    }
11066
11067    pub fn convert_to_upper_case(
11068        &mut self,
11069        _: &ConvertToUpperCase,
11070        window: &mut Window,
11071        cx: &mut Context<Self>,
11072    ) {
11073        self.manipulate_text(window, cx, |text| text.to_uppercase())
11074    }
11075
11076    pub fn convert_to_lower_case(
11077        &mut self,
11078        _: &ConvertToLowerCase,
11079        window: &mut Window,
11080        cx: &mut Context<Self>,
11081    ) {
11082        self.manipulate_text(window, cx, |text| text.to_lowercase())
11083    }
11084
11085    pub fn convert_to_title_case(
11086        &mut self,
11087        _: &ConvertToTitleCase,
11088        window: &mut Window,
11089        cx: &mut Context<Self>,
11090    ) {
11091        self.manipulate_text(window, cx, |text| {
11092            text.split('\n')
11093                .map(|line| line.to_case(Case::Title))
11094                .join("\n")
11095        })
11096    }
11097
11098    pub fn convert_to_snake_case(
11099        &mut self,
11100        _: &ConvertToSnakeCase,
11101        window: &mut Window,
11102        cx: &mut Context<Self>,
11103    ) {
11104        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11105    }
11106
11107    pub fn convert_to_kebab_case(
11108        &mut self,
11109        _: &ConvertToKebabCase,
11110        window: &mut Window,
11111        cx: &mut Context<Self>,
11112    ) {
11113        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11114    }
11115
11116    pub fn convert_to_upper_camel_case(
11117        &mut self,
11118        _: &ConvertToUpperCamelCase,
11119        window: &mut Window,
11120        cx: &mut Context<Self>,
11121    ) {
11122        self.manipulate_text(window, cx, |text| {
11123            text.split('\n')
11124                .map(|line| line.to_case(Case::UpperCamel))
11125                .join("\n")
11126        })
11127    }
11128
11129    pub fn convert_to_lower_camel_case(
11130        &mut self,
11131        _: &ConvertToLowerCamelCase,
11132        window: &mut Window,
11133        cx: &mut Context<Self>,
11134    ) {
11135        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11136    }
11137
11138    pub fn convert_to_opposite_case(
11139        &mut self,
11140        _: &ConvertToOppositeCase,
11141        window: &mut Window,
11142        cx: &mut Context<Self>,
11143    ) {
11144        self.manipulate_text(window, cx, |text| {
11145            text.chars()
11146                .fold(String::with_capacity(text.len()), |mut t, c| {
11147                    if c.is_uppercase() {
11148                        t.extend(c.to_lowercase());
11149                    } else {
11150                        t.extend(c.to_uppercase());
11151                    }
11152                    t
11153                })
11154        })
11155    }
11156
11157    pub fn convert_to_sentence_case(
11158        &mut self,
11159        _: &ConvertToSentenceCase,
11160        window: &mut Window,
11161        cx: &mut Context<Self>,
11162    ) {
11163        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11164    }
11165
11166    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11167        self.manipulate_text(window, cx, |text| {
11168            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11169            if has_upper_case_characters {
11170                text.to_lowercase()
11171            } else {
11172                text.to_uppercase()
11173            }
11174        })
11175    }
11176
11177    pub fn convert_to_rot13(
11178        &mut self,
11179        _: &ConvertToRot13,
11180        window: &mut Window,
11181        cx: &mut Context<Self>,
11182    ) {
11183        self.manipulate_text(window, cx, |text| {
11184            text.chars()
11185                .map(|c| match c {
11186                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11187                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11188                    _ => c,
11189                })
11190                .collect()
11191        })
11192    }
11193
11194    pub fn convert_to_rot47(
11195        &mut self,
11196        _: &ConvertToRot47,
11197        window: &mut Window,
11198        cx: &mut Context<Self>,
11199    ) {
11200        self.manipulate_text(window, cx, |text| {
11201            text.chars()
11202                .map(|c| {
11203                    let code_point = c as u32;
11204                    if code_point >= 33 && code_point <= 126 {
11205                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11206                    }
11207                    c
11208                })
11209                .collect()
11210        })
11211    }
11212
11213    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11214    where
11215        Fn: FnMut(&str) -> String,
11216    {
11217        let buffer = self.buffer.read(cx).snapshot(cx);
11218
11219        let mut new_selections = Vec::new();
11220        let mut edits = Vec::new();
11221        let mut selection_adjustment = 0i32;
11222
11223        for selection in self.selections.all::<usize>(cx) {
11224            let selection_is_empty = selection.is_empty();
11225
11226            let (start, end) = if selection_is_empty {
11227                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11228                (word_range.start, word_range.end)
11229            } else {
11230                (selection.start, selection.end)
11231            };
11232
11233            let text = buffer.text_for_range(start..end).collect::<String>();
11234            let old_length = text.len() as i32;
11235            let text = callback(&text);
11236
11237            new_selections.push(Selection {
11238                start: (start as i32 - selection_adjustment) as usize,
11239                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11240                goal: SelectionGoal::None,
11241                ..selection
11242            });
11243
11244            selection_adjustment += old_length - text.len() as i32;
11245
11246            edits.push((start..end, text));
11247        }
11248
11249        self.transact(window, cx, |this, window, cx| {
11250            this.buffer.update(cx, |buffer, cx| {
11251                buffer.edit(edits, None, cx);
11252            });
11253
11254            this.change_selections(Default::default(), window, cx, |s| {
11255                s.select(new_selections);
11256            });
11257
11258            this.request_autoscroll(Autoscroll::fit(), cx);
11259        });
11260    }
11261
11262    pub fn move_selection_on_drop(
11263        &mut self,
11264        selection: &Selection<Anchor>,
11265        target: DisplayPoint,
11266        is_cut: bool,
11267        window: &mut Window,
11268        cx: &mut Context<Self>,
11269    ) {
11270        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11271        let buffer = &display_map.buffer_snapshot;
11272        let mut edits = Vec::new();
11273        let insert_point = display_map
11274            .clip_point(target, Bias::Left)
11275            .to_point(&display_map);
11276        let text = buffer
11277            .text_for_range(selection.start..selection.end)
11278            .collect::<String>();
11279        if is_cut {
11280            edits.push(((selection.start..selection.end), String::new()));
11281        }
11282        let insert_anchor = buffer.anchor_before(insert_point);
11283        edits.push(((insert_anchor..insert_anchor), text));
11284        let last_edit_start = insert_anchor.bias_left(buffer);
11285        let last_edit_end = insert_anchor.bias_right(buffer);
11286        self.transact(window, cx, |this, window, cx| {
11287            this.buffer.update(cx, |buffer, cx| {
11288                buffer.edit(edits, None, cx);
11289            });
11290            this.change_selections(Default::default(), window, cx, |s| {
11291                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11292            });
11293        });
11294    }
11295
11296    pub fn clear_selection_drag_state(&mut self) {
11297        self.selection_drag_state = SelectionDragState::None;
11298    }
11299
11300    pub fn duplicate(
11301        &mut self,
11302        upwards: bool,
11303        whole_lines: bool,
11304        window: &mut Window,
11305        cx: &mut Context<Self>,
11306    ) {
11307        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11308
11309        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11310        let buffer = &display_map.buffer_snapshot;
11311        let selections = self.selections.all::<Point>(cx);
11312
11313        let mut edits = Vec::new();
11314        let mut selections_iter = selections.iter().peekable();
11315        while let Some(selection) = selections_iter.next() {
11316            let mut rows = selection.spanned_rows(false, &display_map);
11317            // duplicate line-wise
11318            if whole_lines || selection.start == selection.end {
11319                // Avoid duplicating the same lines twice.
11320                while let Some(next_selection) = selections_iter.peek() {
11321                    let next_rows = next_selection.spanned_rows(false, &display_map);
11322                    if next_rows.start < rows.end {
11323                        rows.end = next_rows.end;
11324                        selections_iter.next().unwrap();
11325                    } else {
11326                        break;
11327                    }
11328                }
11329
11330                // Copy the text from the selected row region and splice it either at the start
11331                // or end of the region.
11332                let start = Point::new(rows.start.0, 0);
11333                let end = Point::new(
11334                    rows.end.previous_row().0,
11335                    buffer.line_len(rows.end.previous_row()),
11336                );
11337                let text = buffer
11338                    .text_for_range(start..end)
11339                    .chain(Some("\n"))
11340                    .collect::<String>();
11341                let insert_location = if upwards {
11342                    Point::new(rows.end.0, 0)
11343                } else {
11344                    start
11345                };
11346                edits.push((insert_location..insert_location, text));
11347            } else {
11348                // duplicate character-wise
11349                let start = selection.start;
11350                let end = selection.end;
11351                let text = buffer.text_for_range(start..end).collect::<String>();
11352                edits.push((selection.end..selection.end, text));
11353            }
11354        }
11355
11356        self.transact(window, cx, |this, _, cx| {
11357            this.buffer.update(cx, |buffer, cx| {
11358                buffer.edit(edits, None, cx);
11359            });
11360
11361            this.request_autoscroll(Autoscroll::fit(), cx);
11362        });
11363    }
11364
11365    pub fn duplicate_line_up(
11366        &mut self,
11367        _: &DuplicateLineUp,
11368        window: &mut Window,
11369        cx: &mut Context<Self>,
11370    ) {
11371        self.duplicate(true, true, window, cx);
11372    }
11373
11374    pub fn duplicate_line_down(
11375        &mut self,
11376        _: &DuplicateLineDown,
11377        window: &mut Window,
11378        cx: &mut Context<Self>,
11379    ) {
11380        self.duplicate(false, true, window, cx);
11381    }
11382
11383    pub fn duplicate_selection(
11384        &mut self,
11385        _: &DuplicateSelection,
11386        window: &mut Window,
11387        cx: &mut Context<Self>,
11388    ) {
11389        self.duplicate(false, false, window, cx);
11390    }
11391
11392    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11393        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11394        if self.mode.is_single_line() {
11395            cx.propagate();
11396            return;
11397        }
11398
11399        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11400        let buffer = self.buffer.read(cx).snapshot(cx);
11401
11402        let mut edits = Vec::new();
11403        let mut unfold_ranges = Vec::new();
11404        let mut refold_creases = Vec::new();
11405
11406        let selections = self.selections.all::<Point>(cx);
11407        let mut selections = selections.iter().peekable();
11408        let mut contiguous_row_selections = Vec::new();
11409        let mut new_selections = Vec::new();
11410
11411        while let Some(selection) = selections.next() {
11412            // Find all the selections that span a contiguous row range
11413            let (start_row, end_row) = consume_contiguous_rows(
11414                &mut contiguous_row_selections,
11415                selection,
11416                &display_map,
11417                &mut selections,
11418            );
11419
11420            // Move the text spanned by the row range to be before the line preceding the row range
11421            if start_row.0 > 0 {
11422                let range_to_move = Point::new(
11423                    start_row.previous_row().0,
11424                    buffer.line_len(start_row.previous_row()),
11425                )
11426                    ..Point::new(
11427                        end_row.previous_row().0,
11428                        buffer.line_len(end_row.previous_row()),
11429                    );
11430                let insertion_point = display_map
11431                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11432                    .0;
11433
11434                // Don't move lines across excerpts
11435                if buffer
11436                    .excerpt_containing(insertion_point..range_to_move.end)
11437                    .is_some()
11438                {
11439                    let text = buffer
11440                        .text_for_range(range_to_move.clone())
11441                        .flat_map(|s| s.chars())
11442                        .skip(1)
11443                        .chain(['\n'])
11444                        .collect::<String>();
11445
11446                    edits.push((
11447                        buffer.anchor_after(range_to_move.start)
11448                            ..buffer.anchor_before(range_to_move.end),
11449                        String::new(),
11450                    ));
11451                    let insertion_anchor = buffer.anchor_after(insertion_point);
11452                    edits.push((insertion_anchor..insertion_anchor, text));
11453
11454                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11455
11456                    // Move selections up
11457                    new_selections.extend(contiguous_row_selections.drain(..).map(
11458                        |mut selection| {
11459                            selection.start.row -= row_delta;
11460                            selection.end.row -= row_delta;
11461                            selection
11462                        },
11463                    ));
11464
11465                    // Move folds up
11466                    unfold_ranges.push(range_to_move.clone());
11467                    for fold in display_map.folds_in_range(
11468                        buffer.anchor_before(range_to_move.start)
11469                            ..buffer.anchor_after(range_to_move.end),
11470                    ) {
11471                        let mut start = fold.range.start.to_point(&buffer);
11472                        let mut end = fold.range.end.to_point(&buffer);
11473                        start.row -= row_delta;
11474                        end.row -= row_delta;
11475                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11476                    }
11477                }
11478            }
11479
11480            // If we didn't move line(s), preserve the existing selections
11481            new_selections.append(&mut contiguous_row_selections);
11482        }
11483
11484        self.transact(window, cx, |this, window, cx| {
11485            this.unfold_ranges(&unfold_ranges, true, true, cx);
11486            this.buffer.update(cx, |buffer, cx| {
11487                for (range, text) in edits {
11488                    buffer.edit([(range, text)], None, cx);
11489                }
11490            });
11491            this.fold_creases(refold_creases, true, window, cx);
11492            this.change_selections(Default::default(), window, cx, |s| {
11493                s.select(new_selections);
11494            })
11495        });
11496    }
11497
11498    pub fn move_line_down(
11499        &mut self,
11500        _: &MoveLineDown,
11501        window: &mut Window,
11502        cx: &mut Context<Self>,
11503    ) {
11504        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11505        if self.mode.is_single_line() {
11506            cx.propagate();
11507            return;
11508        }
11509
11510        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11511        let buffer = self.buffer.read(cx).snapshot(cx);
11512
11513        let mut edits = Vec::new();
11514        let mut unfold_ranges = Vec::new();
11515        let mut refold_creases = Vec::new();
11516
11517        let selections = self.selections.all::<Point>(cx);
11518        let mut selections = selections.iter().peekable();
11519        let mut contiguous_row_selections = Vec::new();
11520        let mut new_selections = Vec::new();
11521
11522        while let Some(selection) = selections.next() {
11523            // Find all the selections that span a contiguous row range
11524            let (start_row, end_row) = consume_contiguous_rows(
11525                &mut contiguous_row_selections,
11526                selection,
11527                &display_map,
11528                &mut selections,
11529            );
11530
11531            // Move the text spanned by the row range to be after the last line of the row range
11532            if end_row.0 <= buffer.max_point().row {
11533                let range_to_move =
11534                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11535                let insertion_point = display_map
11536                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11537                    .0;
11538
11539                // Don't move lines across excerpt boundaries
11540                if buffer
11541                    .excerpt_containing(range_to_move.start..insertion_point)
11542                    .is_some()
11543                {
11544                    let mut text = String::from("\n");
11545                    text.extend(buffer.text_for_range(range_to_move.clone()));
11546                    text.pop(); // Drop trailing newline
11547                    edits.push((
11548                        buffer.anchor_after(range_to_move.start)
11549                            ..buffer.anchor_before(range_to_move.end),
11550                        String::new(),
11551                    ));
11552                    let insertion_anchor = buffer.anchor_after(insertion_point);
11553                    edits.push((insertion_anchor..insertion_anchor, text));
11554
11555                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11556
11557                    // Move selections down
11558                    new_selections.extend(contiguous_row_selections.drain(..).map(
11559                        |mut selection| {
11560                            selection.start.row += row_delta;
11561                            selection.end.row += row_delta;
11562                            selection
11563                        },
11564                    ));
11565
11566                    // Move folds down
11567                    unfold_ranges.push(range_to_move.clone());
11568                    for fold in display_map.folds_in_range(
11569                        buffer.anchor_before(range_to_move.start)
11570                            ..buffer.anchor_after(range_to_move.end),
11571                    ) {
11572                        let mut start = fold.range.start.to_point(&buffer);
11573                        let mut end = fold.range.end.to_point(&buffer);
11574                        start.row += row_delta;
11575                        end.row += row_delta;
11576                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11577                    }
11578                }
11579            }
11580
11581            // If we didn't move line(s), preserve the existing selections
11582            new_selections.append(&mut contiguous_row_selections);
11583        }
11584
11585        self.transact(window, cx, |this, window, cx| {
11586            this.unfold_ranges(&unfold_ranges, true, true, cx);
11587            this.buffer.update(cx, |buffer, cx| {
11588                for (range, text) in edits {
11589                    buffer.edit([(range, text)], None, cx);
11590                }
11591            });
11592            this.fold_creases(refold_creases, true, window, cx);
11593            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11594        });
11595    }
11596
11597    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11598        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11599        let text_layout_details = &self.text_layout_details(window);
11600        self.transact(window, cx, |this, window, cx| {
11601            let edits = this.change_selections(Default::default(), window, cx, |s| {
11602                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11603                s.move_with(|display_map, selection| {
11604                    if !selection.is_empty() {
11605                        return;
11606                    }
11607
11608                    let mut head = selection.head();
11609                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11610                    if head.column() == display_map.line_len(head.row()) {
11611                        transpose_offset = display_map
11612                            .buffer_snapshot
11613                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11614                    }
11615
11616                    if transpose_offset == 0 {
11617                        return;
11618                    }
11619
11620                    *head.column_mut() += 1;
11621                    head = display_map.clip_point(head, Bias::Right);
11622                    let goal = SelectionGoal::HorizontalPosition(
11623                        display_map
11624                            .x_for_display_point(head, text_layout_details)
11625                            .into(),
11626                    );
11627                    selection.collapse_to(head, goal);
11628
11629                    let transpose_start = display_map
11630                        .buffer_snapshot
11631                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11632                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11633                        let transpose_end = display_map
11634                            .buffer_snapshot
11635                            .clip_offset(transpose_offset + 1, Bias::Right);
11636                        if let Some(ch) =
11637                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11638                        {
11639                            edits.push((transpose_start..transpose_offset, String::new()));
11640                            edits.push((transpose_end..transpose_end, ch.to_string()));
11641                        }
11642                    }
11643                });
11644                edits
11645            });
11646            this.buffer
11647                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11648            let selections = this.selections.all::<usize>(cx);
11649            this.change_selections(Default::default(), window, cx, |s| {
11650                s.select(selections);
11651            });
11652        });
11653    }
11654
11655    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11656        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11657        if self.mode.is_single_line() {
11658            cx.propagate();
11659            return;
11660        }
11661
11662        self.rewrap_impl(RewrapOptions::default(), cx)
11663    }
11664
11665    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11666        let buffer = self.buffer.read(cx).snapshot(cx);
11667        let selections = self.selections.all::<Point>(cx);
11668
11669        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11670        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11671            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11672                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11673                .peekable();
11674
11675            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11676                row
11677            } else {
11678                return Vec::new();
11679            };
11680
11681            let language_settings = buffer.language_settings_at(selection.head(), cx);
11682            let language_scope = buffer.language_scope_at(selection.head());
11683
11684            let indent_and_prefix_for_row =
11685                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11686                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11687                    let (comment_prefix, rewrap_prefix) =
11688                        if let Some(language_scope) = &language_scope {
11689                            let indent_end = Point::new(row, indent.len);
11690                            let comment_prefix = language_scope
11691                                .line_comment_prefixes()
11692                                .iter()
11693                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11694                                .map(|prefix| prefix.to_string());
11695                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11696                            let line_text_after_indent = buffer
11697                                .text_for_range(indent_end..line_end)
11698                                .collect::<String>();
11699                            let rewrap_prefix = language_scope
11700                                .rewrap_prefixes()
11701                                .iter()
11702                                .find_map(|prefix_regex| {
11703                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11704                                        if mat.start() == 0 {
11705                                            Some(mat.as_str().to_string())
11706                                        } else {
11707                                            None
11708                                        }
11709                                    })
11710                                })
11711                                .flatten();
11712                            (comment_prefix, rewrap_prefix)
11713                        } else {
11714                            (None, None)
11715                        };
11716                    (indent, comment_prefix, rewrap_prefix)
11717                };
11718
11719            let mut ranges = Vec::new();
11720            let from_empty_selection = selection.is_empty();
11721
11722            let mut current_range_start = first_row;
11723            let mut prev_row = first_row;
11724            let (
11725                mut current_range_indent,
11726                mut current_range_comment_prefix,
11727                mut current_range_rewrap_prefix,
11728            ) = indent_and_prefix_for_row(first_row);
11729
11730            for row in non_blank_rows_iter.skip(1) {
11731                let has_paragraph_break = row > prev_row + 1;
11732
11733                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11734                    indent_and_prefix_for_row(row);
11735
11736                let has_indent_change = row_indent != current_range_indent;
11737                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11738
11739                let has_boundary_change = has_comment_change
11740                    || row_rewrap_prefix.is_some()
11741                    || (has_indent_change && current_range_comment_prefix.is_some());
11742
11743                if has_paragraph_break || has_boundary_change {
11744                    ranges.push((
11745                        language_settings.clone(),
11746                        Point::new(current_range_start, 0)
11747                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11748                        current_range_indent,
11749                        current_range_comment_prefix.clone(),
11750                        current_range_rewrap_prefix.clone(),
11751                        from_empty_selection,
11752                    ));
11753                    current_range_start = row;
11754                    current_range_indent = row_indent;
11755                    current_range_comment_prefix = row_comment_prefix;
11756                    current_range_rewrap_prefix = row_rewrap_prefix;
11757                }
11758                prev_row = row;
11759            }
11760
11761            ranges.push((
11762                language_settings.clone(),
11763                Point::new(current_range_start, 0)
11764                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11765                current_range_indent,
11766                current_range_comment_prefix,
11767                current_range_rewrap_prefix,
11768                from_empty_selection,
11769            ));
11770
11771            ranges
11772        });
11773
11774        let mut edits = Vec::new();
11775        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11776
11777        for (
11778            language_settings,
11779            wrap_range,
11780            indent_size,
11781            comment_prefix,
11782            rewrap_prefix,
11783            from_empty_selection,
11784        ) in wrap_ranges
11785        {
11786            let mut start_row = wrap_range.start.row;
11787            let mut end_row = wrap_range.end.row;
11788
11789            // Skip selections that overlap with a range that has already been rewrapped.
11790            let selection_range = start_row..end_row;
11791            if rewrapped_row_ranges
11792                .iter()
11793                .any(|range| range.overlaps(&selection_range))
11794            {
11795                continue;
11796            }
11797
11798            let tab_size = language_settings.tab_size;
11799
11800            let indent_prefix = indent_size.chars().collect::<String>();
11801            let mut line_prefix = indent_prefix.clone();
11802            let mut inside_comment = false;
11803            if let Some(prefix) = &comment_prefix {
11804                line_prefix.push_str(prefix);
11805                inside_comment = true;
11806            }
11807            if let Some(prefix) = &rewrap_prefix {
11808                line_prefix.push_str(prefix);
11809            }
11810
11811            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11812                RewrapBehavior::InComments => inside_comment,
11813                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11814                RewrapBehavior::Anywhere => true,
11815            };
11816
11817            let should_rewrap = options.override_language_settings
11818                || allow_rewrap_based_on_language
11819                || self.hard_wrap.is_some();
11820            if !should_rewrap {
11821                continue;
11822            }
11823
11824            if from_empty_selection {
11825                'expand_upwards: while start_row > 0 {
11826                    let prev_row = start_row - 1;
11827                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11828                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11829                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11830                    {
11831                        start_row = prev_row;
11832                    } else {
11833                        break 'expand_upwards;
11834                    }
11835                }
11836
11837                'expand_downwards: while end_row < buffer.max_point().row {
11838                    let next_row = end_row + 1;
11839                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11840                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11841                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11842                    {
11843                        end_row = next_row;
11844                    } else {
11845                        break 'expand_downwards;
11846                    }
11847                }
11848            }
11849
11850            let start = Point::new(start_row, 0);
11851            let start_offset = start.to_offset(&buffer);
11852            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11853            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11854            let Some(lines_without_prefixes) = selection_text
11855                .lines()
11856                .enumerate()
11857                .map(|(ix, line)| {
11858                    let line_trimmed = line.trim_start();
11859                    if rewrap_prefix.is_some() && ix > 0 {
11860                        Ok(line_trimmed)
11861                    } else {
11862                        line_trimmed
11863                            .strip_prefix(&line_prefix.trim_start())
11864                            .with_context(|| {
11865                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11866                            })
11867                    }
11868                })
11869                .collect::<Result<Vec<_>, _>>()
11870                .log_err()
11871            else {
11872                continue;
11873            };
11874
11875            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11876                buffer
11877                    .language_settings_at(Point::new(start_row, 0), cx)
11878                    .preferred_line_length as usize
11879            });
11880
11881            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11882                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11883            } else {
11884                line_prefix.clone()
11885            };
11886
11887            let wrapped_text = wrap_with_prefix(
11888                line_prefix,
11889                subsequent_lines_prefix,
11890                lines_without_prefixes.join("\n"),
11891                wrap_column,
11892                tab_size,
11893                options.preserve_existing_whitespace,
11894            );
11895
11896            // TODO: should always use char-based diff while still supporting cursor behavior that
11897            // matches vim.
11898            let mut diff_options = DiffOptions::default();
11899            if options.override_language_settings {
11900                diff_options.max_word_diff_len = 0;
11901                diff_options.max_word_diff_line_count = 0;
11902            } else {
11903                diff_options.max_word_diff_len = usize::MAX;
11904                diff_options.max_word_diff_line_count = usize::MAX;
11905            }
11906
11907            for (old_range, new_text) in
11908                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11909            {
11910                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11911                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11912                edits.push((edit_start..edit_end, new_text));
11913            }
11914
11915            rewrapped_row_ranges.push(start_row..=end_row);
11916        }
11917
11918        self.buffer
11919            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11920    }
11921
11922    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11923        let mut text = String::new();
11924        let buffer = self.buffer.read(cx).snapshot(cx);
11925        let mut selections = self.selections.all::<Point>(cx);
11926        let mut clipboard_selections = Vec::with_capacity(selections.len());
11927        {
11928            let max_point = buffer.max_point();
11929            let mut is_first = true;
11930            for selection in &mut selections {
11931                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11932                if is_entire_line {
11933                    selection.start = Point::new(selection.start.row, 0);
11934                    if !selection.is_empty() && selection.end.column == 0 {
11935                        selection.end = cmp::min(max_point, selection.end);
11936                    } else {
11937                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11938                    }
11939                    selection.goal = SelectionGoal::None;
11940                }
11941                if is_first {
11942                    is_first = false;
11943                } else {
11944                    text += "\n";
11945                }
11946                let mut len = 0;
11947                for chunk in buffer.text_for_range(selection.start..selection.end) {
11948                    text.push_str(chunk);
11949                    len += chunk.len();
11950                }
11951                clipboard_selections.push(ClipboardSelection {
11952                    len,
11953                    is_entire_line,
11954                    first_line_indent: buffer
11955                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11956                        .len,
11957                });
11958            }
11959        }
11960
11961        self.transact(window, cx, |this, window, cx| {
11962            this.change_selections(Default::default(), window, cx, |s| {
11963                s.select(selections);
11964            });
11965            this.insert("", window, cx);
11966        });
11967        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11968    }
11969
11970    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11971        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11972        let item = self.cut_common(window, cx);
11973        cx.write_to_clipboard(item);
11974    }
11975
11976    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11977        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11978        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11979            s.move_with(|snapshot, sel| {
11980                if sel.is_empty() {
11981                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11982                }
11983            });
11984        });
11985        let item = self.cut_common(window, cx);
11986        cx.set_global(KillRing(item))
11987    }
11988
11989    pub fn kill_ring_yank(
11990        &mut self,
11991        _: &KillRingYank,
11992        window: &mut Window,
11993        cx: &mut Context<Self>,
11994    ) {
11995        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11996        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11997            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11998                (kill_ring.text().to_string(), kill_ring.metadata_json())
11999            } else {
12000                return;
12001            }
12002        } else {
12003            return;
12004        };
12005        self.do_paste(&text, metadata, false, window, cx);
12006    }
12007
12008    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12009        self.do_copy(true, cx);
12010    }
12011
12012    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12013        self.do_copy(false, cx);
12014    }
12015
12016    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12017        let selections = self.selections.all::<Point>(cx);
12018        let buffer = self.buffer.read(cx).read(cx);
12019        let mut text = String::new();
12020
12021        let mut clipboard_selections = Vec::with_capacity(selections.len());
12022        {
12023            let max_point = buffer.max_point();
12024            let mut is_first = true;
12025            for selection in &selections {
12026                let mut start = selection.start;
12027                let mut end = selection.end;
12028                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12029                if is_entire_line {
12030                    start = Point::new(start.row, 0);
12031                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12032                }
12033
12034                let mut trimmed_selections = Vec::new();
12035                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12036                    let row = MultiBufferRow(start.row);
12037                    let first_indent = buffer.indent_size_for_line(row);
12038                    if first_indent.len == 0 || start.column > first_indent.len {
12039                        trimmed_selections.push(start..end);
12040                    } else {
12041                        trimmed_selections.push(
12042                            Point::new(row.0, first_indent.len)
12043                                ..Point::new(row.0, buffer.line_len(row)),
12044                        );
12045                        for row in start.row + 1..=end.row {
12046                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12047                            if row == end.row {
12048                                line_len = end.column;
12049                            }
12050                            if line_len == 0 {
12051                                trimmed_selections
12052                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12053                                continue;
12054                            }
12055                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12056                            if row_indent_size.len >= first_indent.len {
12057                                trimmed_selections.push(
12058                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12059                                );
12060                            } else {
12061                                trimmed_selections.clear();
12062                                trimmed_selections.push(start..end);
12063                                break;
12064                            }
12065                        }
12066                    }
12067                } else {
12068                    trimmed_selections.push(start..end);
12069                }
12070
12071                for trimmed_range in trimmed_selections {
12072                    if is_first {
12073                        is_first = false;
12074                    } else {
12075                        text += "\n";
12076                    }
12077                    let mut len = 0;
12078                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12079                        text.push_str(chunk);
12080                        len += chunk.len();
12081                    }
12082                    clipboard_selections.push(ClipboardSelection {
12083                        len,
12084                        is_entire_line,
12085                        first_line_indent: buffer
12086                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12087                            .len,
12088                    });
12089                }
12090            }
12091        }
12092
12093        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12094            text,
12095            clipboard_selections,
12096        ));
12097    }
12098
12099    pub fn do_paste(
12100        &mut self,
12101        text: &String,
12102        clipboard_selections: Option<Vec<ClipboardSelection>>,
12103        handle_entire_lines: bool,
12104        window: &mut Window,
12105        cx: &mut Context<Self>,
12106    ) {
12107        if self.read_only(cx) {
12108            return;
12109        }
12110
12111        let clipboard_text = Cow::Borrowed(text);
12112
12113        self.transact(window, cx, |this, window, cx| {
12114            if let Some(mut clipboard_selections) = clipboard_selections {
12115                let old_selections = this.selections.all::<usize>(cx);
12116                let all_selections_were_entire_line =
12117                    clipboard_selections.iter().all(|s| s.is_entire_line);
12118                let first_selection_indent_column =
12119                    clipboard_selections.first().map(|s| s.first_line_indent);
12120                if clipboard_selections.len() != old_selections.len() {
12121                    clipboard_selections.drain(..);
12122                }
12123                let cursor_offset = this.selections.last::<usize>(cx).head();
12124                let mut auto_indent_on_paste = true;
12125
12126                this.buffer.update(cx, |buffer, cx| {
12127                    let snapshot = buffer.read(cx);
12128                    auto_indent_on_paste = snapshot
12129                        .language_settings_at(cursor_offset, cx)
12130                        .auto_indent_on_paste;
12131
12132                    let mut start_offset = 0;
12133                    let mut edits = Vec::new();
12134                    let mut original_indent_columns = Vec::new();
12135                    for (ix, selection) in old_selections.iter().enumerate() {
12136                        let to_insert;
12137                        let entire_line;
12138                        let original_indent_column;
12139                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12140                            let end_offset = start_offset + clipboard_selection.len;
12141                            to_insert = &clipboard_text[start_offset..end_offset];
12142                            entire_line = clipboard_selection.is_entire_line;
12143                            start_offset = end_offset + 1;
12144                            original_indent_column = Some(clipboard_selection.first_line_indent);
12145                        } else {
12146                            to_insert = clipboard_text.as_str();
12147                            entire_line = all_selections_were_entire_line;
12148                            original_indent_column = first_selection_indent_column
12149                        }
12150
12151                        // If the corresponding selection was empty when this slice of the
12152                        // clipboard text was written, then the entire line containing the
12153                        // selection was copied. If this selection is also currently empty,
12154                        // then paste the line before the current line of the buffer.
12155                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12156                            let column = selection.start.to_point(&snapshot).column as usize;
12157                            let line_start = selection.start - column;
12158                            line_start..line_start
12159                        } else {
12160                            selection.range()
12161                        };
12162
12163                        edits.push((range, to_insert));
12164                        original_indent_columns.push(original_indent_column);
12165                    }
12166                    drop(snapshot);
12167
12168                    buffer.edit(
12169                        edits,
12170                        if auto_indent_on_paste {
12171                            Some(AutoindentMode::Block {
12172                                original_indent_columns,
12173                            })
12174                        } else {
12175                            None
12176                        },
12177                        cx,
12178                    );
12179                });
12180
12181                let selections = this.selections.all::<usize>(cx);
12182                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12183            } else {
12184                this.insert(&clipboard_text, window, cx);
12185            }
12186        });
12187    }
12188
12189    pub fn diff_clipboard_with_selection(
12190        &mut self,
12191        _: &DiffClipboardWithSelection,
12192        window: &mut Window,
12193        cx: &mut Context<Self>,
12194    ) {
12195        let selections = self.selections.all::<usize>(cx);
12196
12197        if selections.is_empty() {
12198            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12199            return;
12200        };
12201
12202        let clipboard_text = match cx.read_from_clipboard() {
12203            Some(item) => match item.entries().first() {
12204                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12205                _ => None,
12206            },
12207            None => None,
12208        };
12209
12210        let Some(clipboard_text) = clipboard_text else {
12211            log::warn!("Clipboard doesn't contain text.");
12212            return;
12213        };
12214
12215        window.dispatch_action(
12216            Box::new(DiffClipboardWithSelectionData {
12217                clipboard_text,
12218                editor: cx.entity(),
12219            }),
12220            cx,
12221        );
12222    }
12223
12224    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12225        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12226        if let Some(item) = cx.read_from_clipboard() {
12227            let entries = item.entries();
12228
12229            match entries.first() {
12230                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12231                // of all the pasted entries.
12232                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12233                    .do_paste(
12234                        clipboard_string.text(),
12235                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12236                        true,
12237                        window,
12238                        cx,
12239                    ),
12240                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12241            }
12242        }
12243    }
12244
12245    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12246        if self.read_only(cx) {
12247            return;
12248        }
12249
12250        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12251
12252        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12253            if let Some((selections, _)) =
12254                self.selection_history.transaction(transaction_id).cloned()
12255            {
12256                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12257                    s.select_anchors(selections.to_vec());
12258                });
12259            } else {
12260                log::error!(
12261                    "No entry in selection_history found for undo. \
12262                     This may correspond to a bug where undo does not update the selection. \
12263                     If this is occurring, please add details to \
12264                     https://github.com/zed-industries/zed/issues/22692"
12265                );
12266            }
12267            self.request_autoscroll(Autoscroll::fit(), cx);
12268            self.unmark_text(window, cx);
12269            self.refresh_inline_completion(true, false, window, cx);
12270            cx.emit(EditorEvent::Edited { transaction_id });
12271            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12272        }
12273    }
12274
12275    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12276        if self.read_only(cx) {
12277            return;
12278        }
12279
12280        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12281
12282        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12283            if let Some((_, Some(selections))) =
12284                self.selection_history.transaction(transaction_id).cloned()
12285            {
12286                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12287                    s.select_anchors(selections.to_vec());
12288                });
12289            } else {
12290                log::error!(
12291                    "No entry in selection_history found for redo. \
12292                     This may correspond to a bug where undo does not update the selection. \
12293                     If this is occurring, please add details to \
12294                     https://github.com/zed-industries/zed/issues/22692"
12295                );
12296            }
12297            self.request_autoscroll(Autoscroll::fit(), cx);
12298            self.unmark_text(window, cx);
12299            self.refresh_inline_completion(true, false, window, cx);
12300            cx.emit(EditorEvent::Edited { transaction_id });
12301        }
12302    }
12303
12304    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12305        self.buffer
12306            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12307    }
12308
12309    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12310        self.buffer
12311            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12312    }
12313
12314    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12315        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12316        self.change_selections(Default::default(), window, cx, |s| {
12317            s.move_with(|map, selection| {
12318                let cursor = if selection.is_empty() {
12319                    movement::left(map, selection.start)
12320                } else {
12321                    selection.start
12322                };
12323                selection.collapse_to(cursor, SelectionGoal::None);
12324            });
12325        })
12326    }
12327
12328    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12329        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12330        self.change_selections(Default::default(), window, cx, |s| {
12331            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12332        })
12333    }
12334
12335    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12336        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12337        self.change_selections(Default::default(), window, cx, |s| {
12338            s.move_with(|map, selection| {
12339                let cursor = if selection.is_empty() {
12340                    movement::right(map, selection.end)
12341                } else {
12342                    selection.end
12343                };
12344                selection.collapse_to(cursor, SelectionGoal::None)
12345            });
12346        })
12347    }
12348
12349    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12350        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12351        self.change_selections(Default::default(), window, cx, |s| {
12352            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12353        })
12354    }
12355
12356    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12357        if self.take_rename(true, window, cx).is_some() {
12358            return;
12359        }
12360
12361        if self.mode.is_single_line() {
12362            cx.propagate();
12363            return;
12364        }
12365
12366        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12367
12368        let text_layout_details = &self.text_layout_details(window);
12369        let selection_count = self.selections.count();
12370        let first_selection = self.selections.first_anchor();
12371
12372        self.change_selections(Default::default(), window, cx, |s| {
12373            s.move_with(|map, selection| {
12374                if !selection.is_empty() {
12375                    selection.goal = SelectionGoal::None;
12376                }
12377                let (cursor, goal) = movement::up(
12378                    map,
12379                    selection.start,
12380                    selection.goal,
12381                    false,
12382                    text_layout_details,
12383                );
12384                selection.collapse_to(cursor, goal);
12385            });
12386        });
12387
12388        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12389        {
12390            cx.propagate();
12391        }
12392    }
12393
12394    pub fn move_up_by_lines(
12395        &mut self,
12396        action: &MoveUpByLines,
12397        window: &mut Window,
12398        cx: &mut Context<Self>,
12399    ) {
12400        if self.take_rename(true, window, cx).is_some() {
12401            return;
12402        }
12403
12404        if self.mode.is_single_line() {
12405            cx.propagate();
12406            return;
12407        }
12408
12409        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12410
12411        let text_layout_details = &self.text_layout_details(window);
12412
12413        self.change_selections(Default::default(), window, cx, |s| {
12414            s.move_with(|map, selection| {
12415                if !selection.is_empty() {
12416                    selection.goal = SelectionGoal::None;
12417                }
12418                let (cursor, goal) = movement::up_by_rows(
12419                    map,
12420                    selection.start,
12421                    action.lines,
12422                    selection.goal,
12423                    false,
12424                    text_layout_details,
12425                );
12426                selection.collapse_to(cursor, goal);
12427            });
12428        })
12429    }
12430
12431    pub fn move_down_by_lines(
12432        &mut self,
12433        action: &MoveDownByLines,
12434        window: &mut Window,
12435        cx: &mut Context<Self>,
12436    ) {
12437        if self.take_rename(true, window, cx).is_some() {
12438            return;
12439        }
12440
12441        if self.mode.is_single_line() {
12442            cx.propagate();
12443            return;
12444        }
12445
12446        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12447
12448        let text_layout_details = &self.text_layout_details(window);
12449
12450        self.change_selections(Default::default(), window, cx, |s| {
12451            s.move_with(|map, selection| {
12452                if !selection.is_empty() {
12453                    selection.goal = SelectionGoal::None;
12454                }
12455                let (cursor, goal) = movement::down_by_rows(
12456                    map,
12457                    selection.start,
12458                    action.lines,
12459                    selection.goal,
12460                    false,
12461                    text_layout_details,
12462                );
12463                selection.collapse_to(cursor, goal);
12464            });
12465        })
12466    }
12467
12468    pub fn select_down_by_lines(
12469        &mut self,
12470        action: &SelectDownByLines,
12471        window: &mut Window,
12472        cx: &mut Context<Self>,
12473    ) {
12474        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12475        let text_layout_details = &self.text_layout_details(window);
12476        self.change_selections(Default::default(), window, cx, |s| {
12477            s.move_heads_with(|map, head, goal| {
12478                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12479            })
12480        })
12481    }
12482
12483    pub fn select_up_by_lines(
12484        &mut self,
12485        action: &SelectUpByLines,
12486        window: &mut Window,
12487        cx: &mut Context<Self>,
12488    ) {
12489        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12490        let text_layout_details = &self.text_layout_details(window);
12491        self.change_selections(Default::default(), window, cx, |s| {
12492            s.move_heads_with(|map, head, goal| {
12493                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12494            })
12495        })
12496    }
12497
12498    pub fn select_page_up(
12499        &mut self,
12500        _: &SelectPageUp,
12501        window: &mut Window,
12502        cx: &mut Context<Self>,
12503    ) {
12504        let Some(row_count) = self.visible_row_count() else {
12505            return;
12506        };
12507
12508        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12509
12510        let text_layout_details = &self.text_layout_details(window);
12511
12512        self.change_selections(Default::default(), window, cx, |s| {
12513            s.move_heads_with(|map, head, goal| {
12514                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12515            })
12516        })
12517    }
12518
12519    pub fn move_page_up(
12520        &mut self,
12521        action: &MovePageUp,
12522        window: &mut Window,
12523        cx: &mut Context<Self>,
12524    ) {
12525        if self.take_rename(true, window, cx).is_some() {
12526            return;
12527        }
12528
12529        if self
12530            .context_menu
12531            .borrow_mut()
12532            .as_mut()
12533            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12534            .unwrap_or(false)
12535        {
12536            return;
12537        }
12538
12539        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12540            cx.propagate();
12541            return;
12542        }
12543
12544        let Some(row_count) = self.visible_row_count() else {
12545            return;
12546        };
12547
12548        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12549
12550        let effects = if action.center_cursor {
12551            SelectionEffects::scroll(Autoscroll::center())
12552        } else {
12553            SelectionEffects::default()
12554        };
12555
12556        let text_layout_details = &self.text_layout_details(window);
12557
12558        self.change_selections(effects, window, cx, |s| {
12559            s.move_with(|map, selection| {
12560                if !selection.is_empty() {
12561                    selection.goal = SelectionGoal::None;
12562                }
12563                let (cursor, goal) = movement::up_by_rows(
12564                    map,
12565                    selection.end,
12566                    row_count,
12567                    selection.goal,
12568                    false,
12569                    text_layout_details,
12570                );
12571                selection.collapse_to(cursor, goal);
12572            });
12573        });
12574    }
12575
12576    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12577        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12578        let text_layout_details = &self.text_layout_details(window);
12579        self.change_selections(Default::default(), window, cx, |s| {
12580            s.move_heads_with(|map, head, goal| {
12581                movement::up(map, head, goal, false, text_layout_details)
12582            })
12583        })
12584    }
12585
12586    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12587        self.take_rename(true, window, cx);
12588
12589        if self.mode.is_single_line() {
12590            cx.propagate();
12591            return;
12592        }
12593
12594        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12595
12596        let text_layout_details = &self.text_layout_details(window);
12597        let selection_count = self.selections.count();
12598        let first_selection = self.selections.first_anchor();
12599
12600        self.change_selections(Default::default(), window, cx, |s| {
12601            s.move_with(|map, selection| {
12602                if !selection.is_empty() {
12603                    selection.goal = SelectionGoal::None;
12604                }
12605                let (cursor, goal) = movement::down(
12606                    map,
12607                    selection.end,
12608                    selection.goal,
12609                    false,
12610                    text_layout_details,
12611                );
12612                selection.collapse_to(cursor, goal);
12613            });
12614        });
12615
12616        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12617        {
12618            cx.propagate();
12619        }
12620    }
12621
12622    pub fn select_page_down(
12623        &mut self,
12624        _: &SelectPageDown,
12625        window: &mut Window,
12626        cx: &mut Context<Self>,
12627    ) {
12628        let Some(row_count) = self.visible_row_count() else {
12629            return;
12630        };
12631
12632        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12633
12634        let text_layout_details = &self.text_layout_details(window);
12635
12636        self.change_selections(Default::default(), window, cx, |s| {
12637            s.move_heads_with(|map, head, goal| {
12638                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12639            })
12640        })
12641    }
12642
12643    pub fn move_page_down(
12644        &mut self,
12645        action: &MovePageDown,
12646        window: &mut Window,
12647        cx: &mut Context<Self>,
12648    ) {
12649        if self.take_rename(true, window, cx).is_some() {
12650            return;
12651        }
12652
12653        if self
12654            .context_menu
12655            .borrow_mut()
12656            .as_mut()
12657            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12658            .unwrap_or(false)
12659        {
12660            return;
12661        }
12662
12663        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12664            cx.propagate();
12665            return;
12666        }
12667
12668        let Some(row_count) = self.visible_row_count() else {
12669            return;
12670        };
12671
12672        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12673
12674        let effects = if action.center_cursor {
12675            SelectionEffects::scroll(Autoscroll::center())
12676        } else {
12677            SelectionEffects::default()
12678        };
12679
12680        let text_layout_details = &self.text_layout_details(window);
12681        self.change_selections(effects, window, cx, |s| {
12682            s.move_with(|map, selection| {
12683                if !selection.is_empty() {
12684                    selection.goal = SelectionGoal::None;
12685                }
12686                let (cursor, goal) = movement::down_by_rows(
12687                    map,
12688                    selection.end,
12689                    row_count,
12690                    selection.goal,
12691                    false,
12692                    text_layout_details,
12693                );
12694                selection.collapse_to(cursor, goal);
12695            });
12696        });
12697    }
12698
12699    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12700        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12701        let text_layout_details = &self.text_layout_details(window);
12702        self.change_selections(Default::default(), window, cx, |s| {
12703            s.move_heads_with(|map, head, goal| {
12704                movement::down(map, head, goal, false, text_layout_details)
12705            })
12706        });
12707    }
12708
12709    pub fn context_menu_first(
12710        &mut self,
12711        _: &ContextMenuFirst,
12712        window: &mut Window,
12713        cx: &mut Context<Self>,
12714    ) {
12715        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12716            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12717        }
12718    }
12719
12720    pub fn context_menu_prev(
12721        &mut self,
12722        _: &ContextMenuPrevious,
12723        window: &mut Window,
12724        cx: &mut Context<Self>,
12725    ) {
12726        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12727            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12728        }
12729    }
12730
12731    pub fn context_menu_next(
12732        &mut self,
12733        _: &ContextMenuNext,
12734        window: &mut Window,
12735        cx: &mut Context<Self>,
12736    ) {
12737        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12738            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12739        }
12740    }
12741
12742    pub fn context_menu_last(
12743        &mut self,
12744        _: &ContextMenuLast,
12745        window: &mut Window,
12746        cx: &mut Context<Self>,
12747    ) {
12748        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12749            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12750        }
12751    }
12752
12753    pub fn signature_help_prev(
12754        &mut self,
12755        _: &SignatureHelpPrevious,
12756        _: &mut Window,
12757        cx: &mut Context<Self>,
12758    ) {
12759        if let Some(popover) = self.signature_help_state.popover_mut() {
12760            if popover.current_signature == 0 {
12761                popover.current_signature = popover.signatures.len() - 1;
12762            } else {
12763                popover.current_signature -= 1;
12764            }
12765            cx.notify();
12766        }
12767    }
12768
12769    pub fn signature_help_next(
12770        &mut self,
12771        _: &SignatureHelpNext,
12772        _: &mut Window,
12773        cx: &mut Context<Self>,
12774    ) {
12775        if let Some(popover) = self.signature_help_state.popover_mut() {
12776            if popover.current_signature + 1 == popover.signatures.len() {
12777                popover.current_signature = 0;
12778            } else {
12779                popover.current_signature += 1;
12780            }
12781            cx.notify();
12782        }
12783    }
12784
12785    pub fn move_to_previous_word_start(
12786        &mut self,
12787        _: &MoveToPreviousWordStart,
12788        window: &mut Window,
12789        cx: &mut Context<Self>,
12790    ) {
12791        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12792        self.change_selections(Default::default(), window, cx, |s| {
12793            s.move_cursors_with(|map, head, _| {
12794                (
12795                    movement::previous_word_start(map, head),
12796                    SelectionGoal::None,
12797                )
12798            });
12799        })
12800    }
12801
12802    pub fn move_to_previous_subword_start(
12803        &mut self,
12804        _: &MoveToPreviousSubwordStart,
12805        window: &mut Window,
12806        cx: &mut Context<Self>,
12807    ) {
12808        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12809        self.change_selections(Default::default(), window, cx, |s| {
12810            s.move_cursors_with(|map, head, _| {
12811                (
12812                    movement::previous_subword_start(map, head),
12813                    SelectionGoal::None,
12814                )
12815            });
12816        })
12817    }
12818
12819    pub fn select_to_previous_word_start(
12820        &mut self,
12821        _: &SelectToPreviousWordStart,
12822        window: &mut Window,
12823        cx: &mut Context<Self>,
12824    ) {
12825        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12826        self.change_selections(Default::default(), window, cx, |s| {
12827            s.move_heads_with(|map, head, _| {
12828                (
12829                    movement::previous_word_start(map, head),
12830                    SelectionGoal::None,
12831                )
12832            });
12833        })
12834    }
12835
12836    pub fn select_to_previous_subword_start(
12837        &mut self,
12838        _: &SelectToPreviousSubwordStart,
12839        window: &mut Window,
12840        cx: &mut Context<Self>,
12841    ) {
12842        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12843        self.change_selections(Default::default(), window, cx, |s| {
12844            s.move_heads_with(|map, head, _| {
12845                (
12846                    movement::previous_subword_start(map, head),
12847                    SelectionGoal::None,
12848                )
12849            });
12850        })
12851    }
12852
12853    pub fn delete_to_previous_word_start(
12854        &mut self,
12855        action: &DeleteToPreviousWordStart,
12856        window: &mut Window,
12857        cx: &mut Context<Self>,
12858    ) {
12859        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12860        self.transact(window, cx, |this, window, cx| {
12861            this.select_autoclose_pair(window, cx);
12862            this.change_selections(Default::default(), window, cx, |s| {
12863                s.move_with(|map, selection| {
12864                    if selection.is_empty() {
12865                        let cursor = if action.ignore_newlines {
12866                            movement::previous_word_start(map, selection.head())
12867                        } else {
12868                            movement::previous_word_start_or_newline(map, selection.head())
12869                        };
12870                        selection.set_head(cursor, SelectionGoal::None);
12871                    }
12872                });
12873            });
12874            this.insert("", window, cx);
12875        });
12876    }
12877
12878    pub fn delete_to_previous_subword_start(
12879        &mut self,
12880        _: &DeleteToPreviousSubwordStart,
12881        window: &mut Window,
12882        cx: &mut Context<Self>,
12883    ) {
12884        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12885        self.transact(window, cx, |this, window, cx| {
12886            this.select_autoclose_pair(window, cx);
12887            this.change_selections(Default::default(), window, cx, |s| {
12888                s.move_with(|map, selection| {
12889                    if selection.is_empty() {
12890                        let cursor = movement::previous_subword_start(map, selection.head());
12891                        selection.set_head(cursor, SelectionGoal::None);
12892                    }
12893                });
12894            });
12895            this.insert("", window, cx);
12896        });
12897    }
12898
12899    pub fn move_to_next_word_end(
12900        &mut self,
12901        _: &MoveToNextWordEnd,
12902        window: &mut Window,
12903        cx: &mut Context<Self>,
12904    ) {
12905        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12906        self.change_selections(Default::default(), window, cx, |s| {
12907            s.move_cursors_with(|map, head, _| {
12908                (movement::next_word_end(map, head), SelectionGoal::None)
12909            });
12910        })
12911    }
12912
12913    pub fn move_to_next_subword_end(
12914        &mut self,
12915        _: &MoveToNextSubwordEnd,
12916        window: &mut Window,
12917        cx: &mut Context<Self>,
12918    ) {
12919        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12920        self.change_selections(Default::default(), window, cx, |s| {
12921            s.move_cursors_with(|map, head, _| {
12922                (movement::next_subword_end(map, head), SelectionGoal::None)
12923            });
12924        })
12925    }
12926
12927    pub fn select_to_next_word_end(
12928        &mut self,
12929        _: &SelectToNextWordEnd,
12930        window: &mut Window,
12931        cx: &mut Context<Self>,
12932    ) {
12933        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12934        self.change_selections(Default::default(), window, cx, |s| {
12935            s.move_heads_with(|map, head, _| {
12936                (movement::next_word_end(map, head), SelectionGoal::None)
12937            });
12938        })
12939    }
12940
12941    pub fn select_to_next_subword_end(
12942        &mut self,
12943        _: &SelectToNextSubwordEnd,
12944        window: &mut Window,
12945        cx: &mut Context<Self>,
12946    ) {
12947        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12948        self.change_selections(Default::default(), window, cx, |s| {
12949            s.move_heads_with(|map, head, _| {
12950                (movement::next_subword_end(map, head), SelectionGoal::None)
12951            });
12952        })
12953    }
12954
12955    pub fn delete_to_next_word_end(
12956        &mut self,
12957        action: &DeleteToNextWordEnd,
12958        window: &mut Window,
12959        cx: &mut Context<Self>,
12960    ) {
12961        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12962        self.transact(window, cx, |this, window, cx| {
12963            this.change_selections(Default::default(), window, cx, |s| {
12964                s.move_with(|map, selection| {
12965                    if selection.is_empty() {
12966                        let cursor = if action.ignore_newlines {
12967                            movement::next_word_end(map, selection.head())
12968                        } else {
12969                            movement::next_word_end_or_newline(map, selection.head())
12970                        };
12971                        selection.set_head(cursor, SelectionGoal::None);
12972                    }
12973                });
12974            });
12975            this.insert("", window, cx);
12976        });
12977    }
12978
12979    pub fn delete_to_next_subword_end(
12980        &mut self,
12981        _: &DeleteToNextSubwordEnd,
12982        window: &mut Window,
12983        cx: &mut Context<Self>,
12984    ) {
12985        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12986        self.transact(window, cx, |this, window, cx| {
12987            this.change_selections(Default::default(), window, cx, |s| {
12988                s.move_with(|map, selection| {
12989                    if selection.is_empty() {
12990                        let cursor = movement::next_subword_end(map, selection.head());
12991                        selection.set_head(cursor, SelectionGoal::None);
12992                    }
12993                });
12994            });
12995            this.insert("", window, cx);
12996        });
12997    }
12998
12999    pub fn move_to_beginning_of_line(
13000        &mut self,
13001        action: &MoveToBeginningOfLine,
13002        window: &mut Window,
13003        cx: &mut Context<Self>,
13004    ) {
13005        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13006        self.change_selections(Default::default(), window, cx, |s| {
13007            s.move_cursors_with(|map, head, _| {
13008                (
13009                    movement::indented_line_beginning(
13010                        map,
13011                        head,
13012                        action.stop_at_soft_wraps,
13013                        action.stop_at_indent,
13014                    ),
13015                    SelectionGoal::None,
13016                )
13017            });
13018        })
13019    }
13020
13021    pub fn select_to_beginning_of_line(
13022        &mut self,
13023        action: &SelectToBeginningOfLine,
13024        window: &mut Window,
13025        cx: &mut Context<Self>,
13026    ) {
13027        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13028        self.change_selections(Default::default(), window, cx, |s| {
13029            s.move_heads_with(|map, head, _| {
13030                (
13031                    movement::indented_line_beginning(
13032                        map,
13033                        head,
13034                        action.stop_at_soft_wraps,
13035                        action.stop_at_indent,
13036                    ),
13037                    SelectionGoal::None,
13038                )
13039            });
13040        });
13041    }
13042
13043    pub fn delete_to_beginning_of_line(
13044        &mut self,
13045        action: &DeleteToBeginningOfLine,
13046        window: &mut Window,
13047        cx: &mut Context<Self>,
13048    ) {
13049        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13050        self.transact(window, cx, |this, window, cx| {
13051            this.change_selections(Default::default(), window, cx, |s| {
13052                s.move_with(|_, selection| {
13053                    selection.reversed = true;
13054                });
13055            });
13056
13057            this.select_to_beginning_of_line(
13058                &SelectToBeginningOfLine {
13059                    stop_at_soft_wraps: false,
13060                    stop_at_indent: action.stop_at_indent,
13061                },
13062                window,
13063                cx,
13064            );
13065            this.backspace(&Backspace, window, cx);
13066        });
13067    }
13068
13069    pub fn move_to_end_of_line(
13070        &mut self,
13071        action: &MoveToEndOfLine,
13072        window: &mut Window,
13073        cx: &mut Context<Self>,
13074    ) {
13075        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13076        self.change_selections(Default::default(), window, cx, |s| {
13077            s.move_cursors_with(|map, head, _| {
13078                (
13079                    movement::line_end(map, head, action.stop_at_soft_wraps),
13080                    SelectionGoal::None,
13081                )
13082            });
13083        })
13084    }
13085
13086    pub fn select_to_end_of_line(
13087        &mut self,
13088        action: &SelectToEndOfLine,
13089        window: &mut Window,
13090        cx: &mut Context<Self>,
13091    ) {
13092        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13093        self.change_selections(Default::default(), window, cx, |s| {
13094            s.move_heads_with(|map, head, _| {
13095                (
13096                    movement::line_end(map, head, action.stop_at_soft_wraps),
13097                    SelectionGoal::None,
13098                )
13099            });
13100        })
13101    }
13102
13103    pub fn delete_to_end_of_line(
13104        &mut self,
13105        _: &DeleteToEndOfLine,
13106        window: &mut Window,
13107        cx: &mut Context<Self>,
13108    ) {
13109        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13110        self.transact(window, cx, |this, window, cx| {
13111            this.select_to_end_of_line(
13112                &SelectToEndOfLine {
13113                    stop_at_soft_wraps: false,
13114                },
13115                window,
13116                cx,
13117            );
13118            this.delete(&Delete, window, cx);
13119        });
13120    }
13121
13122    pub fn cut_to_end_of_line(
13123        &mut self,
13124        _: &CutToEndOfLine,
13125        window: &mut Window,
13126        cx: &mut Context<Self>,
13127    ) {
13128        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13129        self.transact(window, cx, |this, window, cx| {
13130            this.select_to_end_of_line(
13131                &SelectToEndOfLine {
13132                    stop_at_soft_wraps: false,
13133                },
13134                window,
13135                cx,
13136            );
13137            this.cut(&Cut, window, cx);
13138        });
13139    }
13140
13141    pub fn move_to_start_of_paragraph(
13142        &mut self,
13143        _: &MoveToStartOfParagraph,
13144        window: &mut Window,
13145        cx: &mut Context<Self>,
13146    ) {
13147        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13148            cx.propagate();
13149            return;
13150        }
13151        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13152        self.change_selections(Default::default(), window, cx, |s| {
13153            s.move_with(|map, selection| {
13154                selection.collapse_to(
13155                    movement::start_of_paragraph(map, selection.head(), 1),
13156                    SelectionGoal::None,
13157                )
13158            });
13159        })
13160    }
13161
13162    pub fn move_to_end_of_paragraph(
13163        &mut self,
13164        _: &MoveToEndOfParagraph,
13165        window: &mut Window,
13166        cx: &mut Context<Self>,
13167    ) {
13168        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13169            cx.propagate();
13170            return;
13171        }
13172        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13173        self.change_selections(Default::default(), window, cx, |s| {
13174            s.move_with(|map, selection| {
13175                selection.collapse_to(
13176                    movement::end_of_paragraph(map, selection.head(), 1),
13177                    SelectionGoal::None,
13178                )
13179            });
13180        })
13181    }
13182
13183    pub fn select_to_start_of_paragraph(
13184        &mut self,
13185        _: &SelectToStartOfParagraph,
13186        window: &mut Window,
13187        cx: &mut Context<Self>,
13188    ) {
13189        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13190            cx.propagate();
13191            return;
13192        }
13193        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13194        self.change_selections(Default::default(), window, cx, |s| {
13195            s.move_heads_with(|map, head, _| {
13196                (
13197                    movement::start_of_paragraph(map, head, 1),
13198                    SelectionGoal::None,
13199                )
13200            });
13201        })
13202    }
13203
13204    pub fn select_to_end_of_paragraph(
13205        &mut self,
13206        _: &SelectToEndOfParagraph,
13207        window: &mut Window,
13208        cx: &mut Context<Self>,
13209    ) {
13210        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13211            cx.propagate();
13212            return;
13213        }
13214        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13215        self.change_selections(Default::default(), window, cx, |s| {
13216            s.move_heads_with(|map, head, _| {
13217                (
13218                    movement::end_of_paragraph(map, head, 1),
13219                    SelectionGoal::None,
13220                )
13221            });
13222        })
13223    }
13224
13225    pub fn move_to_start_of_excerpt(
13226        &mut self,
13227        _: &MoveToStartOfExcerpt,
13228        window: &mut Window,
13229        cx: &mut Context<Self>,
13230    ) {
13231        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13232            cx.propagate();
13233            return;
13234        }
13235        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13236        self.change_selections(Default::default(), window, cx, |s| {
13237            s.move_with(|map, selection| {
13238                selection.collapse_to(
13239                    movement::start_of_excerpt(
13240                        map,
13241                        selection.head(),
13242                        workspace::searchable::Direction::Prev,
13243                    ),
13244                    SelectionGoal::None,
13245                )
13246            });
13247        })
13248    }
13249
13250    pub fn move_to_start_of_next_excerpt(
13251        &mut self,
13252        _: &MoveToStartOfNextExcerpt,
13253        window: &mut Window,
13254        cx: &mut Context<Self>,
13255    ) {
13256        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13257            cx.propagate();
13258            return;
13259        }
13260
13261        self.change_selections(Default::default(), window, cx, |s| {
13262            s.move_with(|map, selection| {
13263                selection.collapse_to(
13264                    movement::start_of_excerpt(
13265                        map,
13266                        selection.head(),
13267                        workspace::searchable::Direction::Next,
13268                    ),
13269                    SelectionGoal::None,
13270                )
13271            });
13272        })
13273    }
13274
13275    pub fn move_to_end_of_excerpt(
13276        &mut self,
13277        _: &MoveToEndOfExcerpt,
13278        window: &mut Window,
13279        cx: &mut Context<Self>,
13280    ) {
13281        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13282            cx.propagate();
13283            return;
13284        }
13285        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13286        self.change_selections(Default::default(), window, cx, |s| {
13287            s.move_with(|map, selection| {
13288                selection.collapse_to(
13289                    movement::end_of_excerpt(
13290                        map,
13291                        selection.head(),
13292                        workspace::searchable::Direction::Next,
13293                    ),
13294                    SelectionGoal::None,
13295                )
13296            });
13297        })
13298    }
13299
13300    pub fn move_to_end_of_previous_excerpt(
13301        &mut self,
13302        _: &MoveToEndOfPreviousExcerpt,
13303        window: &mut Window,
13304        cx: &mut Context<Self>,
13305    ) {
13306        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13307            cx.propagate();
13308            return;
13309        }
13310        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13311        self.change_selections(Default::default(), window, cx, |s| {
13312            s.move_with(|map, selection| {
13313                selection.collapse_to(
13314                    movement::end_of_excerpt(
13315                        map,
13316                        selection.head(),
13317                        workspace::searchable::Direction::Prev,
13318                    ),
13319                    SelectionGoal::None,
13320                )
13321            });
13322        })
13323    }
13324
13325    pub fn select_to_start_of_excerpt(
13326        &mut self,
13327        _: &SelectToStartOfExcerpt,
13328        window: &mut Window,
13329        cx: &mut Context<Self>,
13330    ) {
13331        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13332            cx.propagate();
13333            return;
13334        }
13335        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13336        self.change_selections(Default::default(), window, cx, |s| {
13337            s.move_heads_with(|map, head, _| {
13338                (
13339                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13340                    SelectionGoal::None,
13341                )
13342            });
13343        })
13344    }
13345
13346    pub fn select_to_start_of_next_excerpt(
13347        &mut self,
13348        _: &SelectToStartOfNextExcerpt,
13349        window: &mut Window,
13350        cx: &mut Context<Self>,
13351    ) {
13352        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13353            cx.propagate();
13354            return;
13355        }
13356        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13357        self.change_selections(Default::default(), window, cx, |s| {
13358            s.move_heads_with(|map, head, _| {
13359                (
13360                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13361                    SelectionGoal::None,
13362                )
13363            });
13364        })
13365    }
13366
13367    pub fn select_to_end_of_excerpt(
13368        &mut self,
13369        _: &SelectToEndOfExcerpt,
13370        window: &mut Window,
13371        cx: &mut Context<Self>,
13372    ) {
13373        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13374            cx.propagate();
13375            return;
13376        }
13377        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13378        self.change_selections(Default::default(), window, cx, |s| {
13379            s.move_heads_with(|map, head, _| {
13380                (
13381                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13382                    SelectionGoal::None,
13383                )
13384            });
13385        })
13386    }
13387
13388    pub fn select_to_end_of_previous_excerpt(
13389        &mut self,
13390        _: &SelectToEndOfPreviousExcerpt,
13391        window: &mut Window,
13392        cx: &mut Context<Self>,
13393    ) {
13394        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13395            cx.propagate();
13396            return;
13397        }
13398        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13399        self.change_selections(Default::default(), window, cx, |s| {
13400            s.move_heads_with(|map, head, _| {
13401                (
13402                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13403                    SelectionGoal::None,
13404                )
13405            });
13406        })
13407    }
13408
13409    pub fn move_to_beginning(
13410        &mut self,
13411        _: &MoveToBeginning,
13412        window: &mut Window,
13413        cx: &mut Context<Self>,
13414    ) {
13415        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13416            cx.propagate();
13417            return;
13418        }
13419        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13420        self.change_selections(Default::default(), window, cx, |s| {
13421            s.select_ranges(vec![0..0]);
13422        });
13423    }
13424
13425    pub fn select_to_beginning(
13426        &mut self,
13427        _: &SelectToBeginning,
13428        window: &mut Window,
13429        cx: &mut Context<Self>,
13430    ) {
13431        let mut selection = self.selections.last::<Point>(cx);
13432        selection.set_head(Point::zero(), SelectionGoal::None);
13433        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13434        self.change_selections(Default::default(), window, cx, |s| {
13435            s.select(vec![selection]);
13436        });
13437    }
13438
13439    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13440        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13441            cx.propagate();
13442            return;
13443        }
13444        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13445        let cursor = self.buffer.read(cx).read(cx).len();
13446        self.change_selections(Default::default(), window, cx, |s| {
13447            s.select_ranges(vec![cursor..cursor])
13448        });
13449    }
13450
13451    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13452        self.nav_history = nav_history;
13453    }
13454
13455    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13456        self.nav_history.as_ref()
13457    }
13458
13459    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13460        self.push_to_nav_history(
13461            self.selections.newest_anchor().head(),
13462            None,
13463            false,
13464            true,
13465            cx,
13466        );
13467    }
13468
13469    fn push_to_nav_history(
13470        &mut self,
13471        cursor_anchor: Anchor,
13472        new_position: Option<Point>,
13473        is_deactivate: bool,
13474        always: bool,
13475        cx: &mut Context<Self>,
13476    ) {
13477        if let Some(nav_history) = self.nav_history.as_mut() {
13478            let buffer = self.buffer.read(cx).read(cx);
13479            let cursor_position = cursor_anchor.to_point(&buffer);
13480            let scroll_state = self.scroll_manager.anchor();
13481            let scroll_top_row = scroll_state.top_row(&buffer);
13482            drop(buffer);
13483
13484            if let Some(new_position) = new_position {
13485                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13486                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13487                    return;
13488                }
13489            }
13490
13491            nav_history.push(
13492                Some(NavigationData {
13493                    cursor_anchor,
13494                    cursor_position,
13495                    scroll_anchor: scroll_state,
13496                    scroll_top_row,
13497                }),
13498                cx,
13499            );
13500            cx.emit(EditorEvent::PushedToNavHistory {
13501                anchor: cursor_anchor,
13502                is_deactivate,
13503            })
13504        }
13505    }
13506
13507    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13508        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13509        let buffer = self.buffer.read(cx).snapshot(cx);
13510        let mut selection = self.selections.first::<usize>(cx);
13511        selection.set_head(buffer.len(), SelectionGoal::None);
13512        self.change_selections(Default::default(), window, cx, |s| {
13513            s.select(vec![selection]);
13514        });
13515    }
13516
13517    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13518        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13519        let end = self.buffer.read(cx).read(cx).len();
13520        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13521            s.select_ranges(vec![0..end]);
13522        });
13523    }
13524
13525    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13526        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13527        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13528        let mut selections = self.selections.all::<Point>(cx);
13529        let max_point = display_map.buffer_snapshot.max_point();
13530        for selection in &mut selections {
13531            let rows = selection.spanned_rows(true, &display_map);
13532            selection.start = Point::new(rows.start.0, 0);
13533            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13534            selection.reversed = false;
13535        }
13536        self.change_selections(Default::default(), window, cx, |s| {
13537            s.select(selections);
13538        });
13539    }
13540
13541    pub fn split_selection_into_lines(
13542        &mut self,
13543        _: &SplitSelectionIntoLines,
13544        window: &mut Window,
13545        cx: &mut Context<Self>,
13546    ) {
13547        let selections = self
13548            .selections
13549            .all::<Point>(cx)
13550            .into_iter()
13551            .map(|selection| selection.start..selection.end)
13552            .collect::<Vec<_>>();
13553        self.unfold_ranges(&selections, true, true, cx);
13554
13555        let mut new_selection_ranges = Vec::new();
13556        {
13557            let buffer = self.buffer.read(cx).read(cx);
13558            for selection in selections {
13559                for row in selection.start.row..selection.end.row {
13560                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13561                    new_selection_ranges.push(cursor..cursor);
13562                }
13563
13564                let is_multiline_selection = selection.start.row != selection.end.row;
13565                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13566                // so this action feels more ergonomic when paired with other selection operations
13567                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13568                if !should_skip_last {
13569                    new_selection_ranges.push(selection.end..selection.end);
13570                }
13571            }
13572        }
13573        self.change_selections(Default::default(), window, cx, |s| {
13574            s.select_ranges(new_selection_ranges);
13575        });
13576    }
13577
13578    pub fn add_selection_above(
13579        &mut self,
13580        _: &AddSelectionAbove,
13581        window: &mut Window,
13582        cx: &mut Context<Self>,
13583    ) {
13584        self.add_selection(true, window, cx);
13585    }
13586
13587    pub fn add_selection_below(
13588        &mut self,
13589        _: &AddSelectionBelow,
13590        window: &mut Window,
13591        cx: &mut Context<Self>,
13592    ) {
13593        self.add_selection(false, window, cx);
13594    }
13595
13596    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13597        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13598
13599        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13600        let all_selections = self.selections.all::<Point>(cx);
13601        let text_layout_details = self.text_layout_details(window);
13602
13603        let (mut columnar_selections, new_selections_to_columnarize) = {
13604            if let Some(state) = self.add_selections_state.as_ref() {
13605                let columnar_selection_ids: HashSet<_> = state
13606                    .groups
13607                    .iter()
13608                    .flat_map(|group| group.stack.iter())
13609                    .copied()
13610                    .collect();
13611
13612                all_selections
13613                    .into_iter()
13614                    .partition(|s| columnar_selection_ids.contains(&s.id))
13615            } else {
13616                (Vec::new(), all_selections)
13617            }
13618        };
13619
13620        let mut state = self
13621            .add_selections_state
13622            .take()
13623            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13624
13625        for selection in new_selections_to_columnarize {
13626            let range = selection.display_range(&display_map).sorted();
13627            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13628            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13629            let positions = start_x.min(end_x)..start_x.max(end_x);
13630            let mut stack = Vec::new();
13631            for row in range.start.row().0..=range.end.row().0 {
13632                if let Some(selection) = self.selections.build_columnar_selection(
13633                    &display_map,
13634                    DisplayRow(row),
13635                    &positions,
13636                    selection.reversed,
13637                    &text_layout_details,
13638                ) {
13639                    stack.push(selection.id);
13640                    columnar_selections.push(selection);
13641                }
13642            }
13643            if !stack.is_empty() {
13644                if above {
13645                    stack.reverse();
13646                }
13647                state.groups.push(AddSelectionsGroup { above, stack });
13648            }
13649        }
13650
13651        let mut final_selections = Vec::new();
13652        let end_row = if above {
13653            DisplayRow(0)
13654        } else {
13655            display_map.max_point().row()
13656        };
13657
13658        let mut last_added_item_per_group = HashMap::default();
13659        for group in state.groups.iter_mut() {
13660            if let Some(last_id) = group.stack.last() {
13661                last_added_item_per_group.insert(*last_id, group);
13662            }
13663        }
13664
13665        for selection in columnar_selections {
13666            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13667                if above == group.above {
13668                    let range = selection.display_range(&display_map).sorted();
13669                    debug_assert_eq!(range.start.row(), range.end.row());
13670                    let mut row = range.start.row();
13671                    let positions =
13672                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13673                            px(start)..px(end)
13674                        } else {
13675                            let start_x =
13676                                display_map.x_for_display_point(range.start, &text_layout_details);
13677                            let end_x =
13678                                display_map.x_for_display_point(range.end, &text_layout_details);
13679                            start_x.min(end_x)..start_x.max(end_x)
13680                        };
13681
13682                    let mut maybe_new_selection = None;
13683                    while row != end_row {
13684                        if above {
13685                            row.0 -= 1;
13686                        } else {
13687                            row.0 += 1;
13688                        }
13689                        if let Some(new_selection) = self.selections.build_columnar_selection(
13690                            &display_map,
13691                            row,
13692                            &positions,
13693                            selection.reversed,
13694                            &text_layout_details,
13695                        ) {
13696                            maybe_new_selection = Some(new_selection);
13697                            break;
13698                        }
13699                    }
13700
13701                    if let Some(new_selection) = maybe_new_selection {
13702                        group.stack.push(new_selection.id);
13703                        if above {
13704                            final_selections.push(new_selection);
13705                            final_selections.push(selection);
13706                        } else {
13707                            final_selections.push(selection);
13708                            final_selections.push(new_selection);
13709                        }
13710                    } else {
13711                        final_selections.push(selection);
13712                    }
13713                } else {
13714                    group.stack.pop();
13715                }
13716            } else {
13717                final_selections.push(selection);
13718            }
13719        }
13720
13721        self.change_selections(Default::default(), window, cx, |s| {
13722            s.select(final_selections);
13723        });
13724
13725        let final_selection_ids: HashSet<_> = self
13726            .selections
13727            .all::<Point>(cx)
13728            .iter()
13729            .map(|s| s.id)
13730            .collect();
13731        state.groups.retain_mut(|group| {
13732            // selections might get merged above so we remove invalid items from stacks
13733            group.stack.retain(|id| final_selection_ids.contains(id));
13734
13735            // single selection in stack can be treated as initial state
13736            group.stack.len() > 1
13737        });
13738
13739        if !state.groups.is_empty() {
13740            self.add_selections_state = Some(state);
13741        }
13742    }
13743
13744    fn select_match_ranges(
13745        &mut self,
13746        range: Range<usize>,
13747        reversed: bool,
13748        replace_newest: bool,
13749        auto_scroll: Option<Autoscroll>,
13750        window: &mut Window,
13751        cx: &mut Context<Editor>,
13752    ) {
13753        self.unfold_ranges(
13754            std::slice::from_ref(&range),
13755            false,
13756            auto_scroll.is_some(),
13757            cx,
13758        );
13759        let effects = if let Some(scroll) = auto_scroll {
13760            SelectionEffects::scroll(scroll)
13761        } else {
13762            SelectionEffects::no_scroll()
13763        };
13764        self.change_selections(effects, window, cx, |s| {
13765            if replace_newest {
13766                s.delete(s.newest_anchor().id);
13767            }
13768            if reversed {
13769                s.insert_range(range.end..range.start);
13770            } else {
13771                s.insert_range(range);
13772            }
13773        });
13774    }
13775
13776    pub fn select_next_match_internal(
13777        &mut self,
13778        display_map: &DisplaySnapshot,
13779        replace_newest: bool,
13780        autoscroll: Option<Autoscroll>,
13781        window: &mut Window,
13782        cx: &mut Context<Self>,
13783    ) -> Result<()> {
13784        let buffer = &display_map.buffer_snapshot;
13785        let mut selections = self.selections.all::<usize>(cx);
13786        if let Some(mut select_next_state) = self.select_next_state.take() {
13787            let query = &select_next_state.query;
13788            if !select_next_state.done {
13789                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13790                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13791                let mut next_selected_range = None;
13792
13793                let bytes_after_last_selection =
13794                    buffer.bytes_in_range(last_selection.end..buffer.len());
13795                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13796                let query_matches = query
13797                    .stream_find_iter(bytes_after_last_selection)
13798                    .map(|result| (last_selection.end, result))
13799                    .chain(
13800                        query
13801                            .stream_find_iter(bytes_before_first_selection)
13802                            .map(|result| (0, result)),
13803                    );
13804
13805                for (start_offset, query_match) in query_matches {
13806                    let query_match = query_match.unwrap(); // can only fail due to I/O
13807                    let offset_range =
13808                        start_offset + query_match.start()..start_offset + query_match.end();
13809
13810                    if !select_next_state.wordwise
13811                        || (!buffer.is_inside_word(offset_range.start, false)
13812                            && !buffer.is_inside_word(offset_range.end, false))
13813                    {
13814                        // TODO: This is n^2, because we might check all the selections
13815                        if !selections
13816                            .iter()
13817                            .any(|selection| selection.range().overlaps(&offset_range))
13818                        {
13819                            next_selected_range = Some(offset_range);
13820                            break;
13821                        }
13822                    }
13823                }
13824
13825                if let Some(next_selected_range) = next_selected_range {
13826                    self.select_match_ranges(
13827                        next_selected_range,
13828                        last_selection.reversed,
13829                        replace_newest,
13830                        autoscroll,
13831                        window,
13832                        cx,
13833                    );
13834                } else {
13835                    select_next_state.done = true;
13836                }
13837            }
13838
13839            self.select_next_state = Some(select_next_state);
13840        } else {
13841            let mut only_carets = true;
13842            let mut same_text_selected = true;
13843            let mut selected_text = None;
13844
13845            let mut selections_iter = selections.iter().peekable();
13846            while let Some(selection) = selections_iter.next() {
13847                if selection.start != selection.end {
13848                    only_carets = false;
13849                }
13850
13851                if same_text_selected {
13852                    if selected_text.is_none() {
13853                        selected_text =
13854                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13855                    }
13856
13857                    if let Some(next_selection) = selections_iter.peek() {
13858                        if next_selection.range().len() == selection.range().len() {
13859                            let next_selected_text = buffer
13860                                .text_for_range(next_selection.range())
13861                                .collect::<String>();
13862                            if Some(next_selected_text) != selected_text {
13863                                same_text_selected = false;
13864                                selected_text = None;
13865                            }
13866                        } else {
13867                            same_text_selected = false;
13868                            selected_text = None;
13869                        }
13870                    }
13871                }
13872            }
13873
13874            if only_carets {
13875                for selection in &mut selections {
13876                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13877                    selection.start = word_range.start;
13878                    selection.end = word_range.end;
13879                    selection.goal = SelectionGoal::None;
13880                    selection.reversed = false;
13881                    self.select_match_ranges(
13882                        selection.start..selection.end,
13883                        selection.reversed,
13884                        replace_newest,
13885                        autoscroll,
13886                        window,
13887                        cx,
13888                    );
13889                }
13890
13891                if selections.len() == 1 {
13892                    let selection = selections
13893                        .last()
13894                        .expect("ensured that there's only one selection");
13895                    let query = buffer
13896                        .text_for_range(selection.start..selection.end)
13897                        .collect::<String>();
13898                    let is_empty = query.is_empty();
13899                    let select_state = SelectNextState {
13900                        query: AhoCorasick::new(&[query])?,
13901                        wordwise: true,
13902                        done: is_empty,
13903                    };
13904                    self.select_next_state = Some(select_state);
13905                } else {
13906                    self.select_next_state = None;
13907                }
13908            } else if let Some(selected_text) = selected_text {
13909                self.select_next_state = Some(SelectNextState {
13910                    query: AhoCorasick::new(&[selected_text])?,
13911                    wordwise: false,
13912                    done: false,
13913                });
13914                self.select_next_match_internal(
13915                    display_map,
13916                    replace_newest,
13917                    autoscroll,
13918                    window,
13919                    cx,
13920                )?;
13921            }
13922        }
13923        Ok(())
13924    }
13925
13926    pub fn select_all_matches(
13927        &mut self,
13928        _action: &SelectAllMatches,
13929        window: &mut Window,
13930        cx: &mut Context<Self>,
13931    ) -> Result<()> {
13932        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13933
13934        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13935
13936        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13937        let Some(select_next_state) = self.select_next_state.as_mut() else {
13938            return Ok(());
13939        };
13940        if select_next_state.done {
13941            return Ok(());
13942        }
13943
13944        let mut new_selections = Vec::new();
13945
13946        let reversed = self.selections.oldest::<usize>(cx).reversed;
13947        let buffer = &display_map.buffer_snapshot;
13948        let query_matches = select_next_state
13949            .query
13950            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13951
13952        for query_match in query_matches.into_iter() {
13953            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13954            let offset_range = if reversed {
13955                query_match.end()..query_match.start()
13956            } else {
13957                query_match.start()..query_match.end()
13958            };
13959
13960            if !select_next_state.wordwise
13961                || (!buffer.is_inside_word(offset_range.start, false)
13962                    && !buffer.is_inside_word(offset_range.end, false))
13963            {
13964                new_selections.push(offset_range.start..offset_range.end);
13965            }
13966        }
13967
13968        select_next_state.done = true;
13969
13970        if new_selections.is_empty() {
13971            log::error!("bug: new_selections is empty in select_all_matches");
13972            return Ok(());
13973        }
13974
13975        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13976        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
13977            selections.select_ranges(new_selections)
13978        });
13979
13980        Ok(())
13981    }
13982
13983    pub fn select_next(
13984        &mut self,
13985        action: &SelectNext,
13986        window: &mut Window,
13987        cx: &mut Context<Self>,
13988    ) -> Result<()> {
13989        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13990        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13991        self.select_next_match_internal(
13992            &display_map,
13993            action.replace_newest,
13994            Some(Autoscroll::newest()),
13995            window,
13996            cx,
13997        )?;
13998        Ok(())
13999    }
14000
14001    pub fn select_previous(
14002        &mut self,
14003        action: &SelectPrevious,
14004        window: &mut Window,
14005        cx: &mut Context<Self>,
14006    ) -> Result<()> {
14007        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14008        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14009        let buffer = &display_map.buffer_snapshot;
14010        let mut selections = self.selections.all::<usize>(cx);
14011        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14012            let query = &select_prev_state.query;
14013            if !select_prev_state.done {
14014                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14015                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14016                let mut next_selected_range = None;
14017                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14018                let bytes_before_last_selection =
14019                    buffer.reversed_bytes_in_range(0..last_selection.start);
14020                let bytes_after_first_selection =
14021                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14022                let query_matches = query
14023                    .stream_find_iter(bytes_before_last_selection)
14024                    .map(|result| (last_selection.start, result))
14025                    .chain(
14026                        query
14027                            .stream_find_iter(bytes_after_first_selection)
14028                            .map(|result| (buffer.len(), result)),
14029                    );
14030                for (end_offset, query_match) in query_matches {
14031                    let query_match = query_match.unwrap(); // can only fail due to I/O
14032                    let offset_range =
14033                        end_offset - query_match.end()..end_offset - query_match.start();
14034
14035                    if !select_prev_state.wordwise
14036                        || (!buffer.is_inside_word(offset_range.start, false)
14037                            && !buffer.is_inside_word(offset_range.end, false))
14038                    {
14039                        next_selected_range = Some(offset_range);
14040                        break;
14041                    }
14042                }
14043
14044                if let Some(next_selected_range) = next_selected_range {
14045                    self.select_match_ranges(
14046                        next_selected_range,
14047                        last_selection.reversed,
14048                        action.replace_newest,
14049                        Some(Autoscroll::newest()),
14050                        window,
14051                        cx,
14052                    );
14053                } else {
14054                    select_prev_state.done = true;
14055                }
14056            }
14057
14058            self.select_prev_state = Some(select_prev_state);
14059        } else {
14060            let mut only_carets = true;
14061            let mut same_text_selected = true;
14062            let mut selected_text = None;
14063
14064            let mut selections_iter = selections.iter().peekable();
14065            while let Some(selection) = selections_iter.next() {
14066                if selection.start != selection.end {
14067                    only_carets = false;
14068                }
14069
14070                if same_text_selected {
14071                    if selected_text.is_none() {
14072                        selected_text =
14073                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14074                    }
14075
14076                    if let Some(next_selection) = selections_iter.peek() {
14077                        if next_selection.range().len() == selection.range().len() {
14078                            let next_selected_text = buffer
14079                                .text_for_range(next_selection.range())
14080                                .collect::<String>();
14081                            if Some(next_selected_text) != selected_text {
14082                                same_text_selected = false;
14083                                selected_text = None;
14084                            }
14085                        } else {
14086                            same_text_selected = false;
14087                            selected_text = None;
14088                        }
14089                    }
14090                }
14091            }
14092
14093            if only_carets {
14094                for selection in &mut selections {
14095                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14096                    selection.start = word_range.start;
14097                    selection.end = word_range.end;
14098                    selection.goal = SelectionGoal::None;
14099                    selection.reversed = false;
14100                    self.select_match_ranges(
14101                        selection.start..selection.end,
14102                        selection.reversed,
14103                        action.replace_newest,
14104                        Some(Autoscroll::newest()),
14105                        window,
14106                        cx,
14107                    );
14108                }
14109                if selections.len() == 1 {
14110                    let selection = selections
14111                        .last()
14112                        .expect("ensured that there's only one selection");
14113                    let query = buffer
14114                        .text_for_range(selection.start..selection.end)
14115                        .collect::<String>();
14116                    let is_empty = query.is_empty();
14117                    let select_state = SelectNextState {
14118                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14119                        wordwise: true,
14120                        done: is_empty,
14121                    };
14122                    self.select_prev_state = Some(select_state);
14123                } else {
14124                    self.select_prev_state = None;
14125                }
14126            } else if let Some(selected_text) = selected_text {
14127                self.select_prev_state = Some(SelectNextState {
14128                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14129                    wordwise: false,
14130                    done: false,
14131                });
14132                self.select_previous(action, window, cx)?;
14133            }
14134        }
14135        Ok(())
14136    }
14137
14138    pub fn find_next_match(
14139        &mut self,
14140        _: &FindNextMatch,
14141        window: &mut Window,
14142        cx: &mut Context<Self>,
14143    ) -> Result<()> {
14144        let selections = self.selections.disjoint_anchors();
14145        match selections.first() {
14146            Some(first) if selections.len() >= 2 => {
14147                self.change_selections(Default::default(), window, cx, |s| {
14148                    s.select_ranges([first.range()]);
14149                });
14150            }
14151            _ => self.select_next(
14152                &SelectNext {
14153                    replace_newest: true,
14154                },
14155                window,
14156                cx,
14157            )?,
14158        }
14159        Ok(())
14160    }
14161
14162    pub fn find_previous_match(
14163        &mut self,
14164        _: &FindPreviousMatch,
14165        window: &mut Window,
14166        cx: &mut Context<Self>,
14167    ) -> Result<()> {
14168        let selections = self.selections.disjoint_anchors();
14169        match selections.last() {
14170            Some(last) if selections.len() >= 2 => {
14171                self.change_selections(Default::default(), window, cx, |s| {
14172                    s.select_ranges([last.range()]);
14173                });
14174            }
14175            _ => self.select_previous(
14176                &SelectPrevious {
14177                    replace_newest: true,
14178                },
14179                window,
14180                cx,
14181            )?,
14182        }
14183        Ok(())
14184    }
14185
14186    pub fn toggle_comments(
14187        &mut self,
14188        action: &ToggleComments,
14189        window: &mut Window,
14190        cx: &mut Context<Self>,
14191    ) {
14192        if self.read_only(cx) {
14193            return;
14194        }
14195        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14196        let text_layout_details = &self.text_layout_details(window);
14197        self.transact(window, cx, |this, window, cx| {
14198            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14199            let mut edits = Vec::new();
14200            let mut selection_edit_ranges = Vec::new();
14201            let mut last_toggled_row = None;
14202            let snapshot = this.buffer.read(cx).read(cx);
14203            let empty_str: Arc<str> = Arc::default();
14204            let mut suffixes_inserted = Vec::new();
14205            let ignore_indent = action.ignore_indent;
14206
14207            fn comment_prefix_range(
14208                snapshot: &MultiBufferSnapshot,
14209                row: MultiBufferRow,
14210                comment_prefix: &str,
14211                comment_prefix_whitespace: &str,
14212                ignore_indent: bool,
14213            ) -> Range<Point> {
14214                let indent_size = if ignore_indent {
14215                    0
14216                } else {
14217                    snapshot.indent_size_for_line(row).len
14218                };
14219
14220                let start = Point::new(row.0, indent_size);
14221
14222                let mut line_bytes = snapshot
14223                    .bytes_in_range(start..snapshot.max_point())
14224                    .flatten()
14225                    .copied();
14226
14227                // If this line currently begins with the line comment prefix, then record
14228                // the range containing the prefix.
14229                if line_bytes
14230                    .by_ref()
14231                    .take(comment_prefix.len())
14232                    .eq(comment_prefix.bytes())
14233                {
14234                    // Include any whitespace that matches the comment prefix.
14235                    let matching_whitespace_len = line_bytes
14236                        .zip(comment_prefix_whitespace.bytes())
14237                        .take_while(|(a, b)| a == b)
14238                        .count() as u32;
14239                    let end = Point::new(
14240                        start.row,
14241                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14242                    );
14243                    start..end
14244                } else {
14245                    start..start
14246                }
14247            }
14248
14249            fn comment_suffix_range(
14250                snapshot: &MultiBufferSnapshot,
14251                row: MultiBufferRow,
14252                comment_suffix: &str,
14253                comment_suffix_has_leading_space: bool,
14254            ) -> Range<Point> {
14255                let end = Point::new(row.0, snapshot.line_len(row));
14256                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14257
14258                let mut line_end_bytes = snapshot
14259                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14260                    .flatten()
14261                    .copied();
14262
14263                let leading_space_len = if suffix_start_column > 0
14264                    && line_end_bytes.next() == Some(b' ')
14265                    && comment_suffix_has_leading_space
14266                {
14267                    1
14268                } else {
14269                    0
14270                };
14271
14272                // If this line currently begins with the line comment prefix, then record
14273                // the range containing the prefix.
14274                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14275                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14276                    start..end
14277                } else {
14278                    end..end
14279                }
14280            }
14281
14282            // TODO: Handle selections that cross excerpts
14283            for selection in &mut selections {
14284                let start_column = snapshot
14285                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14286                    .len;
14287                let language = if let Some(language) =
14288                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14289                {
14290                    language
14291                } else {
14292                    continue;
14293                };
14294
14295                selection_edit_ranges.clear();
14296
14297                // If multiple selections contain a given row, avoid processing that
14298                // row more than once.
14299                let mut start_row = MultiBufferRow(selection.start.row);
14300                if last_toggled_row == Some(start_row) {
14301                    start_row = start_row.next_row();
14302                }
14303                let end_row =
14304                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14305                        MultiBufferRow(selection.end.row - 1)
14306                    } else {
14307                        MultiBufferRow(selection.end.row)
14308                    };
14309                last_toggled_row = Some(end_row);
14310
14311                if start_row > end_row {
14312                    continue;
14313                }
14314
14315                // If the language has line comments, toggle those.
14316                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14317
14318                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14319                if ignore_indent {
14320                    full_comment_prefixes = full_comment_prefixes
14321                        .into_iter()
14322                        .map(|s| Arc::from(s.trim_end()))
14323                        .collect();
14324                }
14325
14326                if !full_comment_prefixes.is_empty() {
14327                    let first_prefix = full_comment_prefixes
14328                        .first()
14329                        .expect("prefixes is non-empty");
14330                    let prefix_trimmed_lengths = full_comment_prefixes
14331                        .iter()
14332                        .map(|p| p.trim_end_matches(' ').len())
14333                        .collect::<SmallVec<[usize; 4]>>();
14334
14335                    let mut all_selection_lines_are_comments = true;
14336
14337                    for row in start_row.0..=end_row.0 {
14338                        let row = MultiBufferRow(row);
14339                        if start_row < end_row && snapshot.is_line_blank(row) {
14340                            continue;
14341                        }
14342
14343                        let prefix_range = full_comment_prefixes
14344                            .iter()
14345                            .zip(prefix_trimmed_lengths.iter().copied())
14346                            .map(|(prefix, trimmed_prefix_len)| {
14347                                comment_prefix_range(
14348                                    snapshot.deref(),
14349                                    row,
14350                                    &prefix[..trimmed_prefix_len],
14351                                    &prefix[trimmed_prefix_len..],
14352                                    ignore_indent,
14353                                )
14354                            })
14355                            .max_by_key(|range| range.end.column - range.start.column)
14356                            .expect("prefixes is non-empty");
14357
14358                        if prefix_range.is_empty() {
14359                            all_selection_lines_are_comments = false;
14360                        }
14361
14362                        selection_edit_ranges.push(prefix_range);
14363                    }
14364
14365                    if all_selection_lines_are_comments {
14366                        edits.extend(
14367                            selection_edit_ranges
14368                                .iter()
14369                                .cloned()
14370                                .map(|range| (range, empty_str.clone())),
14371                        );
14372                    } else {
14373                        let min_column = selection_edit_ranges
14374                            .iter()
14375                            .map(|range| range.start.column)
14376                            .min()
14377                            .unwrap_or(0);
14378                        edits.extend(selection_edit_ranges.iter().map(|range| {
14379                            let position = Point::new(range.start.row, min_column);
14380                            (position..position, first_prefix.clone())
14381                        }));
14382                    }
14383                } else if let Some(BlockCommentConfig {
14384                    start: full_comment_prefix,
14385                    end: comment_suffix,
14386                    ..
14387                }) = language.block_comment()
14388                {
14389                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14390                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14391                    let prefix_range = comment_prefix_range(
14392                        snapshot.deref(),
14393                        start_row,
14394                        comment_prefix,
14395                        comment_prefix_whitespace,
14396                        ignore_indent,
14397                    );
14398                    let suffix_range = comment_suffix_range(
14399                        snapshot.deref(),
14400                        end_row,
14401                        comment_suffix.trim_start_matches(' '),
14402                        comment_suffix.starts_with(' '),
14403                    );
14404
14405                    if prefix_range.is_empty() || suffix_range.is_empty() {
14406                        edits.push((
14407                            prefix_range.start..prefix_range.start,
14408                            full_comment_prefix.clone(),
14409                        ));
14410                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14411                        suffixes_inserted.push((end_row, comment_suffix.len()));
14412                    } else {
14413                        edits.push((prefix_range, empty_str.clone()));
14414                        edits.push((suffix_range, empty_str.clone()));
14415                    }
14416                } else {
14417                    continue;
14418                }
14419            }
14420
14421            drop(snapshot);
14422            this.buffer.update(cx, |buffer, cx| {
14423                buffer.edit(edits, None, cx);
14424            });
14425
14426            // Adjust selections so that they end before any comment suffixes that
14427            // were inserted.
14428            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14429            let mut selections = this.selections.all::<Point>(cx);
14430            let snapshot = this.buffer.read(cx).read(cx);
14431            for selection in &mut selections {
14432                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14433                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14434                        Ordering::Less => {
14435                            suffixes_inserted.next();
14436                            continue;
14437                        }
14438                        Ordering::Greater => break,
14439                        Ordering::Equal => {
14440                            if selection.end.column == snapshot.line_len(row) {
14441                                if selection.is_empty() {
14442                                    selection.start.column -= suffix_len as u32;
14443                                }
14444                                selection.end.column -= suffix_len as u32;
14445                            }
14446                            break;
14447                        }
14448                    }
14449                }
14450            }
14451
14452            drop(snapshot);
14453            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14454
14455            let selections = this.selections.all::<Point>(cx);
14456            let selections_on_single_row = selections.windows(2).all(|selections| {
14457                selections[0].start.row == selections[1].start.row
14458                    && selections[0].end.row == selections[1].end.row
14459                    && selections[0].start.row == selections[0].end.row
14460            });
14461            let selections_selecting = selections
14462                .iter()
14463                .any(|selection| selection.start != selection.end);
14464            let advance_downwards = action.advance_downwards
14465                && selections_on_single_row
14466                && !selections_selecting
14467                && !matches!(this.mode, EditorMode::SingleLine { .. });
14468
14469            if advance_downwards {
14470                let snapshot = this.buffer.read(cx).snapshot(cx);
14471
14472                this.change_selections(Default::default(), window, cx, |s| {
14473                    s.move_cursors_with(|display_snapshot, display_point, _| {
14474                        let mut point = display_point.to_point(display_snapshot);
14475                        point.row += 1;
14476                        point = snapshot.clip_point(point, Bias::Left);
14477                        let display_point = point.to_display_point(display_snapshot);
14478                        let goal = SelectionGoal::HorizontalPosition(
14479                            display_snapshot
14480                                .x_for_display_point(display_point, text_layout_details)
14481                                .into(),
14482                        );
14483                        (display_point, goal)
14484                    })
14485                });
14486            }
14487        });
14488    }
14489
14490    pub fn select_enclosing_symbol(
14491        &mut self,
14492        _: &SelectEnclosingSymbol,
14493        window: &mut Window,
14494        cx: &mut Context<Self>,
14495    ) {
14496        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14497
14498        let buffer = self.buffer.read(cx).snapshot(cx);
14499        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14500
14501        fn update_selection(
14502            selection: &Selection<usize>,
14503            buffer_snap: &MultiBufferSnapshot,
14504        ) -> Option<Selection<usize>> {
14505            let cursor = selection.head();
14506            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14507            for symbol in symbols.iter().rev() {
14508                let start = symbol.range.start.to_offset(buffer_snap);
14509                let end = symbol.range.end.to_offset(buffer_snap);
14510                let new_range = start..end;
14511                if start < selection.start || end > selection.end {
14512                    return Some(Selection {
14513                        id: selection.id,
14514                        start: new_range.start,
14515                        end: new_range.end,
14516                        goal: SelectionGoal::None,
14517                        reversed: selection.reversed,
14518                    });
14519                }
14520            }
14521            None
14522        }
14523
14524        let mut selected_larger_symbol = false;
14525        let new_selections = old_selections
14526            .iter()
14527            .map(|selection| match update_selection(selection, &buffer) {
14528                Some(new_selection) => {
14529                    if new_selection.range() != selection.range() {
14530                        selected_larger_symbol = true;
14531                    }
14532                    new_selection
14533                }
14534                None => selection.clone(),
14535            })
14536            .collect::<Vec<_>>();
14537
14538        if selected_larger_symbol {
14539            self.change_selections(Default::default(), window, cx, |s| {
14540                s.select(new_selections);
14541            });
14542        }
14543    }
14544
14545    pub fn select_larger_syntax_node(
14546        &mut self,
14547        _: &SelectLargerSyntaxNode,
14548        window: &mut Window,
14549        cx: &mut Context<Self>,
14550    ) {
14551        let Some(visible_row_count) = self.visible_row_count() else {
14552            return;
14553        };
14554        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14555        if old_selections.is_empty() {
14556            return;
14557        }
14558
14559        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14560
14561        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14562        let buffer = self.buffer.read(cx).snapshot(cx);
14563
14564        let mut selected_larger_node = false;
14565        let mut new_selections = old_selections
14566            .iter()
14567            .map(|selection| {
14568                let old_range = selection.start..selection.end;
14569
14570                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14571                    // manually select word at selection
14572                    if ["string_content", "inline"].contains(&node.kind()) {
14573                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14574                        // ignore if word is already selected
14575                        if !word_range.is_empty() && old_range != word_range {
14576                            let (last_word_range, _) =
14577                                buffer.surrounding_word(old_range.end, false);
14578                            // only select word if start and end point belongs to same word
14579                            if word_range == last_word_range {
14580                                selected_larger_node = true;
14581                                return Selection {
14582                                    id: selection.id,
14583                                    start: word_range.start,
14584                                    end: word_range.end,
14585                                    goal: SelectionGoal::None,
14586                                    reversed: selection.reversed,
14587                                };
14588                            }
14589                        }
14590                    }
14591                }
14592
14593                let mut new_range = old_range.clone();
14594                while let Some((_node, containing_range)) =
14595                    buffer.syntax_ancestor(new_range.clone())
14596                {
14597                    new_range = match containing_range {
14598                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14599                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14600                    };
14601                    if !display_map.intersects_fold(new_range.start)
14602                        && !display_map.intersects_fold(new_range.end)
14603                    {
14604                        break;
14605                    }
14606                }
14607
14608                selected_larger_node |= new_range != old_range;
14609                Selection {
14610                    id: selection.id,
14611                    start: new_range.start,
14612                    end: new_range.end,
14613                    goal: SelectionGoal::None,
14614                    reversed: selection.reversed,
14615                }
14616            })
14617            .collect::<Vec<_>>();
14618
14619        if !selected_larger_node {
14620            return; // don't put this call in the history
14621        }
14622
14623        // scroll based on transformation done to the last selection created by the user
14624        let (last_old, last_new) = old_selections
14625            .last()
14626            .zip(new_selections.last().cloned())
14627            .expect("old_selections isn't empty");
14628
14629        // revert selection
14630        let is_selection_reversed = {
14631            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14632            new_selections.last_mut().expect("checked above").reversed =
14633                should_newest_selection_be_reversed;
14634            should_newest_selection_be_reversed
14635        };
14636
14637        if selected_larger_node {
14638            self.select_syntax_node_history.disable_clearing = true;
14639            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14640                s.select(new_selections.clone());
14641            });
14642            self.select_syntax_node_history.disable_clearing = false;
14643        }
14644
14645        let start_row = last_new.start.to_display_point(&display_map).row().0;
14646        let end_row = last_new.end.to_display_point(&display_map).row().0;
14647        let selection_height = end_row - start_row + 1;
14648        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14649
14650        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14651        let scroll_behavior = if fits_on_the_screen {
14652            self.request_autoscroll(Autoscroll::fit(), cx);
14653            SelectSyntaxNodeScrollBehavior::FitSelection
14654        } else if is_selection_reversed {
14655            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14656            SelectSyntaxNodeScrollBehavior::CursorTop
14657        } else {
14658            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14659            SelectSyntaxNodeScrollBehavior::CursorBottom
14660        };
14661
14662        self.select_syntax_node_history.push((
14663            old_selections,
14664            scroll_behavior,
14665            is_selection_reversed,
14666        ));
14667    }
14668
14669    pub fn select_smaller_syntax_node(
14670        &mut self,
14671        _: &SelectSmallerSyntaxNode,
14672        window: &mut Window,
14673        cx: &mut Context<Self>,
14674    ) {
14675        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14676
14677        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14678            self.select_syntax_node_history.pop()
14679        {
14680            if let Some(selection) = selections.last_mut() {
14681                selection.reversed = is_selection_reversed;
14682            }
14683
14684            self.select_syntax_node_history.disable_clearing = true;
14685            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14686                s.select(selections.to_vec());
14687            });
14688            self.select_syntax_node_history.disable_clearing = false;
14689
14690            match scroll_behavior {
14691                SelectSyntaxNodeScrollBehavior::CursorTop => {
14692                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14693                }
14694                SelectSyntaxNodeScrollBehavior::FitSelection => {
14695                    self.request_autoscroll(Autoscroll::fit(), cx);
14696                }
14697                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14698                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14699                }
14700            }
14701        }
14702    }
14703
14704    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14705        if !EditorSettings::get_global(cx).gutter.runnables {
14706            self.clear_tasks();
14707            return Task::ready(());
14708        }
14709        let project = self.project.as_ref().map(Entity::downgrade);
14710        let task_sources = self.lsp_task_sources(cx);
14711        let multi_buffer = self.buffer.downgrade();
14712        cx.spawn_in(window, async move |editor, cx| {
14713            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14714            let Some(project) = project.and_then(|p| p.upgrade()) else {
14715                return;
14716            };
14717            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14718                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14719            }) else {
14720                return;
14721            };
14722
14723            let hide_runnables = project
14724                .update(cx, |project, cx| {
14725                    // Do not display any test indicators in non-dev server remote projects.
14726                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14727                })
14728                .unwrap_or(true);
14729            if hide_runnables {
14730                return;
14731            }
14732            let new_rows =
14733                cx.background_spawn({
14734                    let snapshot = display_snapshot.clone();
14735                    async move {
14736                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14737                    }
14738                })
14739                    .await;
14740            let Ok(lsp_tasks) =
14741                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14742            else {
14743                return;
14744            };
14745            let lsp_tasks = lsp_tasks.await;
14746
14747            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14748                lsp_tasks
14749                    .into_iter()
14750                    .flat_map(|(kind, tasks)| {
14751                        tasks.into_iter().filter_map(move |(location, task)| {
14752                            Some((kind.clone(), location?, task))
14753                        })
14754                    })
14755                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14756                        let buffer = location.target.buffer;
14757                        let buffer_snapshot = buffer.read(cx).snapshot();
14758                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14759                            |(excerpt_id, snapshot, _)| {
14760                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14761                                    display_snapshot
14762                                        .buffer_snapshot
14763                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14764                                } else {
14765                                    None
14766                                }
14767                            },
14768                        );
14769                        if let Some(offset) = offset {
14770                            let task_buffer_range =
14771                                location.target.range.to_point(&buffer_snapshot);
14772                            let context_buffer_range =
14773                                task_buffer_range.to_offset(&buffer_snapshot);
14774                            let context_range = BufferOffset(context_buffer_range.start)
14775                                ..BufferOffset(context_buffer_range.end);
14776
14777                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14778                                .or_insert_with(|| RunnableTasks {
14779                                    templates: Vec::new(),
14780                                    offset,
14781                                    column: task_buffer_range.start.column,
14782                                    extra_variables: HashMap::default(),
14783                                    context_range,
14784                                })
14785                                .templates
14786                                .push((kind, task.original_task().clone()));
14787                        }
14788
14789                        acc
14790                    })
14791            }) else {
14792                return;
14793            };
14794
14795            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14796                buffer.language_settings(cx).tasks.prefer_lsp
14797            }) else {
14798                return;
14799            };
14800
14801            let rows = Self::runnable_rows(
14802                project,
14803                display_snapshot,
14804                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14805                new_rows,
14806                cx.clone(),
14807            )
14808            .await;
14809            editor
14810                .update(cx, |editor, _| {
14811                    editor.clear_tasks();
14812                    for (key, mut value) in rows {
14813                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14814                            value.templates.extend(lsp_tasks.templates);
14815                        }
14816
14817                        editor.insert_tasks(key, value);
14818                    }
14819                    for (key, value) in lsp_tasks_by_rows {
14820                        editor.insert_tasks(key, value);
14821                    }
14822                })
14823                .ok();
14824        })
14825    }
14826    fn fetch_runnable_ranges(
14827        snapshot: &DisplaySnapshot,
14828        range: Range<Anchor>,
14829    ) -> Vec<language::RunnableRange> {
14830        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14831    }
14832
14833    fn runnable_rows(
14834        project: Entity<Project>,
14835        snapshot: DisplaySnapshot,
14836        prefer_lsp: bool,
14837        runnable_ranges: Vec<RunnableRange>,
14838        cx: AsyncWindowContext,
14839    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14840        cx.spawn(async move |cx| {
14841            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14842            for mut runnable in runnable_ranges {
14843                let Some(tasks) = cx
14844                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14845                    .ok()
14846                else {
14847                    continue;
14848                };
14849                let mut tasks = tasks.await;
14850
14851                if prefer_lsp {
14852                    tasks.retain(|(task_kind, _)| {
14853                        !matches!(task_kind, TaskSourceKind::Language { .. })
14854                    });
14855                }
14856                if tasks.is_empty() {
14857                    continue;
14858                }
14859
14860                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14861                let Some(row) = snapshot
14862                    .buffer_snapshot
14863                    .buffer_line_for_row(MultiBufferRow(point.row))
14864                    .map(|(_, range)| range.start.row)
14865                else {
14866                    continue;
14867                };
14868
14869                let context_range =
14870                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14871                runnable_rows.push((
14872                    (runnable.buffer_id, row),
14873                    RunnableTasks {
14874                        templates: tasks,
14875                        offset: snapshot
14876                            .buffer_snapshot
14877                            .anchor_before(runnable.run_range.start),
14878                        context_range,
14879                        column: point.column,
14880                        extra_variables: runnable.extra_captures,
14881                    },
14882                ));
14883            }
14884            runnable_rows
14885        })
14886    }
14887
14888    fn templates_with_tags(
14889        project: &Entity<Project>,
14890        runnable: &mut Runnable,
14891        cx: &mut App,
14892    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14893        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14894            let (worktree_id, file) = project
14895                .buffer_for_id(runnable.buffer, cx)
14896                .and_then(|buffer| buffer.read(cx).file())
14897                .map(|file| (file.worktree_id(cx), file.clone()))
14898                .unzip();
14899
14900            (
14901                project.task_store().read(cx).task_inventory().cloned(),
14902                worktree_id,
14903                file,
14904            )
14905        });
14906
14907        let tags = mem::take(&mut runnable.tags);
14908        let language = runnable.language.clone();
14909        cx.spawn(async move |cx| {
14910            let mut templates_with_tags = Vec::new();
14911            if let Some(inventory) = inventory {
14912                for RunnableTag(tag) in tags {
14913                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14914                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14915                    }) else {
14916                        return templates_with_tags;
14917                    };
14918                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14919                        move |(_, template)| {
14920                            template.tags.iter().any(|source_tag| source_tag == &tag)
14921                        },
14922                    ));
14923                }
14924            }
14925            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14926
14927            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14928                // Strongest source wins; if we have worktree tag binding, prefer that to
14929                // global and language bindings;
14930                // if we have a global binding, prefer that to language binding.
14931                let first_mismatch = templates_with_tags
14932                    .iter()
14933                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14934                if let Some(index) = first_mismatch {
14935                    templates_with_tags.truncate(index);
14936                }
14937            }
14938
14939            templates_with_tags
14940        })
14941    }
14942
14943    pub fn move_to_enclosing_bracket(
14944        &mut self,
14945        _: &MoveToEnclosingBracket,
14946        window: &mut Window,
14947        cx: &mut Context<Self>,
14948    ) {
14949        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14950        self.change_selections(Default::default(), window, cx, |s| {
14951            s.move_offsets_with(|snapshot, selection| {
14952                let Some(enclosing_bracket_ranges) =
14953                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14954                else {
14955                    return;
14956                };
14957
14958                let mut best_length = usize::MAX;
14959                let mut best_inside = false;
14960                let mut best_in_bracket_range = false;
14961                let mut best_destination = None;
14962                for (open, close) in enclosing_bracket_ranges {
14963                    let close = close.to_inclusive();
14964                    let length = close.end() - open.start;
14965                    let inside = selection.start >= open.end && selection.end <= *close.start();
14966                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14967                        || close.contains(&selection.head());
14968
14969                    // If best is next to a bracket and current isn't, skip
14970                    if !in_bracket_range && best_in_bracket_range {
14971                        continue;
14972                    }
14973
14974                    // Prefer smaller lengths unless best is inside and current isn't
14975                    if length > best_length && (best_inside || !inside) {
14976                        continue;
14977                    }
14978
14979                    best_length = length;
14980                    best_inside = inside;
14981                    best_in_bracket_range = in_bracket_range;
14982                    best_destination = Some(
14983                        if close.contains(&selection.start) && close.contains(&selection.end) {
14984                            if inside { open.end } else { open.start }
14985                        } else if inside {
14986                            *close.start()
14987                        } else {
14988                            *close.end()
14989                        },
14990                    );
14991                }
14992
14993                if let Some(destination) = best_destination {
14994                    selection.collapse_to(destination, SelectionGoal::None);
14995                }
14996            })
14997        });
14998    }
14999
15000    pub fn undo_selection(
15001        &mut self,
15002        _: &UndoSelection,
15003        window: &mut Window,
15004        cx: &mut Context<Self>,
15005    ) {
15006        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15007        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15008            self.selection_history.mode = SelectionHistoryMode::Undoing;
15009            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15010                this.end_selection(window, cx);
15011                this.change_selections(
15012                    SelectionEffects::scroll(Autoscroll::newest()),
15013                    window,
15014                    cx,
15015                    |s| s.select_anchors(entry.selections.to_vec()),
15016                );
15017            });
15018            self.selection_history.mode = SelectionHistoryMode::Normal;
15019
15020            self.select_next_state = entry.select_next_state;
15021            self.select_prev_state = entry.select_prev_state;
15022            self.add_selections_state = entry.add_selections_state;
15023        }
15024    }
15025
15026    pub fn redo_selection(
15027        &mut self,
15028        _: &RedoSelection,
15029        window: &mut Window,
15030        cx: &mut Context<Self>,
15031    ) {
15032        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15033        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15034            self.selection_history.mode = SelectionHistoryMode::Redoing;
15035            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15036                this.end_selection(window, cx);
15037                this.change_selections(
15038                    SelectionEffects::scroll(Autoscroll::newest()),
15039                    window,
15040                    cx,
15041                    |s| s.select_anchors(entry.selections.to_vec()),
15042                );
15043            });
15044            self.selection_history.mode = SelectionHistoryMode::Normal;
15045
15046            self.select_next_state = entry.select_next_state;
15047            self.select_prev_state = entry.select_prev_state;
15048            self.add_selections_state = entry.add_selections_state;
15049        }
15050    }
15051
15052    pub fn expand_excerpts(
15053        &mut self,
15054        action: &ExpandExcerpts,
15055        _: &mut Window,
15056        cx: &mut Context<Self>,
15057    ) {
15058        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15059    }
15060
15061    pub fn expand_excerpts_down(
15062        &mut self,
15063        action: &ExpandExcerptsDown,
15064        _: &mut Window,
15065        cx: &mut Context<Self>,
15066    ) {
15067        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15068    }
15069
15070    pub fn expand_excerpts_up(
15071        &mut self,
15072        action: &ExpandExcerptsUp,
15073        _: &mut Window,
15074        cx: &mut Context<Self>,
15075    ) {
15076        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15077    }
15078
15079    pub fn expand_excerpts_for_direction(
15080        &mut self,
15081        lines: u32,
15082        direction: ExpandExcerptDirection,
15083
15084        cx: &mut Context<Self>,
15085    ) {
15086        let selections = self.selections.disjoint_anchors();
15087
15088        let lines = if lines == 0 {
15089            EditorSettings::get_global(cx).expand_excerpt_lines
15090        } else {
15091            lines
15092        };
15093
15094        self.buffer.update(cx, |buffer, cx| {
15095            let snapshot = buffer.snapshot(cx);
15096            let mut excerpt_ids = selections
15097                .iter()
15098                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15099                .collect::<Vec<_>>();
15100            excerpt_ids.sort();
15101            excerpt_ids.dedup();
15102            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15103        })
15104    }
15105
15106    pub fn expand_excerpt(
15107        &mut self,
15108        excerpt: ExcerptId,
15109        direction: ExpandExcerptDirection,
15110        window: &mut Window,
15111        cx: &mut Context<Self>,
15112    ) {
15113        let current_scroll_position = self.scroll_position(cx);
15114        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15115        let mut should_scroll_up = false;
15116
15117        if direction == ExpandExcerptDirection::Down {
15118            let multi_buffer = self.buffer.read(cx);
15119            let snapshot = multi_buffer.snapshot(cx);
15120            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
15121                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
15122                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
15123                        let buffer_snapshot = buffer.read(cx).snapshot();
15124                        let excerpt_end_row =
15125                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15126                        let last_row = buffer_snapshot.max_point().row;
15127                        let lines_below = last_row.saturating_sub(excerpt_end_row);
15128                        should_scroll_up = lines_below >= lines_to_expand;
15129                    }
15130                }
15131            }
15132        }
15133
15134        self.buffer.update(cx, |buffer, cx| {
15135            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15136        });
15137
15138        if should_scroll_up {
15139            let new_scroll_position =
15140                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15141            self.set_scroll_position(new_scroll_position, window, cx);
15142        }
15143    }
15144
15145    pub fn go_to_singleton_buffer_point(
15146        &mut self,
15147        point: Point,
15148        window: &mut Window,
15149        cx: &mut Context<Self>,
15150    ) {
15151        self.go_to_singleton_buffer_range(point..point, window, cx);
15152    }
15153
15154    pub fn go_to_singleton_buffer_range(
15155        &mut self,
15156        range: Range<Point>,
15157        window: &mut Window,
15158        cx: &mut Context<Self>,
15159    ) {
15160        let multibuffer = self.buffer().read(cx);
15161        let Some(buffer) = multibuffer.as_singleton() else {
15162            return;
15163        };
15164        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15165            return;
15166        };
15167        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15168            return;
15169        };
15170        self.change_selections(
15171            SelectionEffects::default().nav_history(true),
15172            window,
15173            cx,
15174            |s| s.select_anchor_ranges([start..end]),
15175        );
15176    }
15177
15178    pub fn go_to_diagnostic(
15179        &mut self,
15180        action: &GoToDiagnostic,
15181        window: &mut Window,
15182        cx: &mut Context<Self>,
15183    ) {
15184        if !self.diagnostics_enabled() {
15185            return;
15186        }
15187        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15188        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15189    }
15190
15191    pub fn go_to_prev_diagnostic(
15192        &mut self,
15193        action: &GoToPreviousDiagnostic,
15194        window: &mut Window,
15195        cx: &mut Context<Self>,
15196    ) {
15197        if !self.diagnostics_enabled() {
15198            return;
15199        }
15200        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15201        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15202    }
15203
15204    pub fn go_to_diagnostic_impl(
15205        &mut self,
15206        direction: Direction,
15207        severity: GoToDiagnosticSeverityFilter,
15208        window: &mut Window,
15209        cx: &mut Context<Self>,
15210    ) {
15211        let buffer = self.buffer.read(cx).snapshot(cx);
15212        let selection = self.selections.newest::<usize>(cx);
15213
15214        let mut active_group_id = None;
15215        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
15216            if active_group.active_range.start.to_offset(&buffer) == selection.start {
15217                active_group_id = Some(active_group.group_id);
15218            }
15219        }
15220
15221        fn filtered(
15222            snapshot: EditorSnapshot,
15223            severity: GoToDiagnosticSeverityFilter,
15224            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15225        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15226            diagnostics
15227                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15228                .filter(|entry| entry.range.start != entry.range.end)
15229                .filter(|entry| !entry.diagnostic.is_unnecessary)
15230                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15231        }
15232
15233        let snapshot = self.snapshot(window, cx);
15234        let before = filtered(
15235            snapshot.clone(),
15236            severity,
15237            buffer
15238                .diagnostics_in_range(0..selection.start)
15239                .filter(|entry| entry.range.start <= selection.start),
15240        );
15241        let after = filtered(
15242            snapshot,
15243            severity,
15244            buffer
15245                .diagnostics_in_range(selection.start..buffer.len())
15246                .filter(|entry| entry.range.start >= selection.start),
15247        );
15248
15249        let mut found: Option<DiagnosticEntry<usize>> = None;
15250        if direction == Direction::Prev {
15251            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15252            {
15253                for diagnostic in prev_diagnostics.into_iter().rev() {
15254                    if diagnostic.range.start != selection.start
15255                        || active_group_id
15256                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15257                    {
15258                        found = Some(diagnostic);
15259                        break 'outer;
15260                    }
15261                }
15262            }
15263        } else {
15264            for diagnostic in after.chain(before) {
15265                if diagnostic.range.start != selection.start
15266                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15267                {
15268                    found = Some(diagnostic);
15269                    break;
15270                }
15271            }
15272        }
15273        let Some(next_diagnostic) = found else {
15274            return;
15275        };
15276
15277        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
15278            return;
15279        };
15280        self.change_selections(Default::default(), window, cx, |s| {
15281            s.select_ranges(vec![
15282                next_diagnostic.range.start..next_diagnostic.range.start,
15283            ])
15284        });
15285        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15286        self.refresh_inline_completion(false, true, window, cx);
15287    }
15288
15289    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15290        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15291        let snapshot = self.snapshot(window, cx);
15292        let selection = self.selections.newest::<Point>(cx);
15293        self.go_to_hunk_before_or_after_position(
15294            &snapshot,
15295            selection.head(),
15296            Direction::Next,
15297            window,
15298            cx,
15299        );
15300    }
15301
15302    pub fn go_to_hunk_before_or_after_position(
15303        &mut self,
15304        snapshot: &EditorSnapshot,
15305        position: Point,
15306        direction: Direction,
15307        window: &mut Window,
15308        cx: &mut Context<Editor>,
15309    ) {
15310        let row = if direction == Direction::Next {
15311            self.hunk_after_position(snapshot, position)
15312                .map(|hunk| hunk.row_range.start)
15313        } else {
15314            self.hunk_before_position(snapshot, position)
15315        };
15316
15317        if let Some(row) = row {
15318            let destination = Point::new(row.0, 0);
15319            let autoscroll = Autoscroll::center();
15320
15321            self.unfold_ranges(&[destination..destination], false, false, cx);
15322            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15323                s.select_ranges([destination..destination]);
15324            });
15325        }
15326    }
15327
15328    fn hunk_after_position(
15329        &mut self,
15330        snapshot: &EditorSnapshot,
15331        position: Point,
15332    ) -> Option<MultiBufferDiffHunk> {
15333        snapshot
15334            .buffer_snapshot
15335            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15336            .find(|hunk| hunk.row_range.start.0 > position.row)
15337            .or_else(|| {
15338                snapshot
15339                    .buffer_snapshot
15340                    .diff_hunks_in_range(Point::zero()..position)
15341                    .find(|hunk| hunk.row_range.end.0 < position.row)
15342            })
15343    }
15344
15345    fn go_to_prev_hunk(
15346        &mut self,
15347        _: &GoToPreviousHunk,
15348        window: &mut Window,
15349        cx: &mut Context<Self>,
15350    ) {
15351        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15352        let snapshot = self.snapshot(window, cx);
15353        let selection = self.selections.newest::<Point>(cx);
15354        self.go_to_hunk_before_or_after_position(
15355            &snapshot,
15356            selection.head(),
15357            Direction::Prev,
15358            window,
15359            cx,
15360        );
15361    }
15362
15363    fn hunk_before_position(
15364        &mut self,
15365        snapshot: &EditorSnapshot,
15366        position: Point,
15367    ) -> Option<MultiBufferRow> {
15368        snapshot
15369            .buffer_snapshot
15370            .diff_hunk_before(position)
15371            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15372    }
15373
15374    fn go_to_next_change(
15375        &mut self,
15376        _: &GoToNextChange,
15377        window: &mut Window,
15378        cx: &mut Context<Self>,
15379    ) {
15380        if let Some(selections) = self
15381            .change_list
15382            .next_change(1, Direction::Next)
15383            .map(|s| s.to_vec())
15384        {
15385            self.change_selections(Default::default(), window, cx, |s| {
15386                let map = s.display_map();
15387                s.select_display_ranges(selections.iter().map(|a| {
15388                    let point = a.to_display_point(&map);
15389                    point..point
15390                }))
15391            })
15392        }
15393    }
15394
15395    fn go_to_previous_change(
15396        &mut self,
15397        _: &GoToPreviousChange,
15398        window: &mut Window,
15399        cx: &mut Context<Self>,
15400    ) {
15401        if let Some(selections) = self
15402            .change_list
15403            .next_change(1, Direction::Prev)
15404            .map(|s| s.to_vec())
15405        {
15406            self.change_selections(Default::default(), window, cx, |s| {
15407                let map = s.display_map();
15408                s.select_display_ranges(selections.iter().map(|a| {
15409                    let point = a.to_display_point(&map);
15410                    point..point
15411                }))
15412            })
15413        }
15414    }
15415
15416    fn go_to_line<T: 'static>(
15417        &mut self,
15418        position: Anchor,
15419        highlight_color: Option<Hsla>,
15420        window: &mut Window,
15421        cx: &mut Context<Self>,
15422    ) {
15423        let snapshot = self.snapshot(window, cx).display_snapshot;
15424        let position = position.to_point(&snapshot.buffer_snapshot);
15425        let start = snapshot
15426            .buffer_snapshot
15427            .clip_point(Point::new(position.row, 0), Bias::Left);
15428        let end = start + Point::new(1, 0);
15429        let start = snapshot.buffer_snapshot.anchor_before(start);
15430        let end = snapshot.buffer_snapshot.anchor_before(end);
15431
15432        self.highlight_rows::<T>(
15433            start..end,
15434            highlight_color
15435                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15436            Default::default(),
15437            cx,
15438        );
15439
15440        if self.buffer.read(cx).is_singleton() {
15441            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15442        }
15443    }
15444
15445    pub fn go_to_definition(
15446        &mut self,
15447        _: &GoToDefinition,
15448        window: &mut Window,
15449        cx: &mut Context<Self>,
15450    ) -> Task<Result<Navigated>> {
15451        let definition =
15452            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15453        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15454        cx.spawn_in(window, async move |editor, cx| {
15455            if definition.await? == Navigated::Yes {
15456                return Ok(Navigated::Yes);
15457            }
15458            match fallback_strategy {
15459                GoToDefinitionFallback::None => Ok(Navigated::No),
15460                GoToDefinitionFallback::FindAllReferences => {
15461                    match editor.update_in(cx, |editor, window, cx| {
15462                        editor.find_all_references(&FindAllReferences, window, cx)
15463                    })? {
15464                        Some(references) => references.await,
15465                        None => Ok(Navigated::No),
15466                    }
15467                }
15468            }
15469        })
15470    }
15471
15472    pub fn go_to_declaration(
15473        &mut self,
15474        _: &GoToDeclaration,
15475        window: &mut Window,
15476        cx: &mut Context<Self>,
15477    ) -> Task<Result<Navigated>> {
15478        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15479    }
15480
15481    pub fn go_to_declaration_split(
15482        &mut self,
15483        _: &GoToDeclaration,
15484        window: &mut Window,
15485        cx: &mut Context<Self>,
15486    ) -> Task<Result<Navigated>> {
15487        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15488    }
15489
15490    pub fn go_to_implementation(
15491        &mut self,
15492        _: &GoToImplementation,
15493        window: &mut Window,
15494        cx: &mut Context<Self>,
15495    ) -> Task<Result<Navigated>> {
15496        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15497    }
15498
15499    pub fn go_to_implementation_split(
15500        &mut self,
15501        _: &GoToImplementationSplit,
15502        window: &mut Window,
15503        cx: &mut Context<Self>,
15504    ) -> Task<Result<Navigated>> {
15505        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15506    }
15507
15508    pub fn go_to_type_definition(
15509        &mut self,
15510        _: &GoToTypeDefinition,
15511        window: &mut Window,
15512        cx: &mut Context<Self>,
15513    ) -> Task<Result<Navigated>> {
15514        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15515    }
15516
15517    pub fn go_to_definition_split(
15518        &mut self,
15519        _: &GoToDefinitionSplit,
15520        window: &mut Window,
15521        cx: &mut Context<Self>,
15522    ) -> Task<Result<Navigated>> {
15523        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15524    }
15525
15526    pub fn go_to_type_definition_split(
15527        &mut self,
15528        _: &GoToTypeDefinitionSplit,
15529        window: &mut Window,
15530        cx: &mut Context<Self>,
15531    ) -> Task<Result<Navigated>> {
15532        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15533    }
15534
15535    fn go_to_definition_of_kind(
15536        &mut self,
15537        kind: GotoDefinitionKind,
15538        split: bool,
15539        window: &mut Window,
15540        cx: &mut Context<Self>,
15541    ) -> Task<Result<Navigated>> {
15542        let Some(provider) = self.semantics_provider.clone() else {
15543            return Task::ready(Ok(Navigated::No));
15544        };
15545        let head = self.selections.newest::<usize>(cx).head();
15546        let buffer = self.buffer.read(cx);
15547        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
15548            text_anchor
15549        } else {
15550            return Task::ready(Ok(Navigated::No));
15551        };
15552
15553        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15554            return Task::ready(Ok(Navigated::No));
15555        };
15556
15557        cx.spawn_in(window, async move |editor, cx| {
15558            let definitions = definitions.await?;
15559            let navigated = editor
15560                .update_in(cx, |editor, window, cx| {
15561                    editor.navigate_to_hover_links(
15562                        Some(kind),
15563                        definitions
15564                            .into_iter()
15565                            .filter(|location| {
15566                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15567                            })
15568                            .map(HoverLink::Text)
15569                            .collect::<Vec<_>>(),
15570                        split,
15571                        window,
15572                        cx,
15573                    )
15574                })?
15575                .await?;
15576            anyhow::Ok(navigated)
15577        })
15578    }
15579
15580    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15581        let selection = self.selections.newest_anchor();
15582        let head = selection.head();
15583        let tail = selection.tail();
15584
15585        let Some((buffer, start_position)) =
15586            self.buffer.read(cx).text_anchor_for_position(head, cx)
15587        else {
15588            return;
15589        };
15590
15591        let end_position = if head != tail {
15592            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15593                return;
15594            };
15595            Some(pos)
15596        } else {
15597            None
15598        };
15599
15600        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15601            let url = if let Some(end_pos) = end_position {
15602                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15603            } else {
15604                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15605            };
15606
15607            if let Some(url) = url {
15608                editor.update(cx, |_, cx| {
15609                    cx.open_url(&url);
15610                })
15611            } else {
15612                Ok(())
15613            }
15614        });
15615
15616        url_finder.detach();
15617    }
15618
15619    pub fn open_selected_filename(
15620        &mut self,
15621        _: &OpenSelectedFilename,
15622        window: &mut Window,
15623        cx: &mut Context<Self>,
15624    ) {
15625        let Some(workspace) = self.workspace() else {
15626            return;
15627        };
15628
15629        let position = self.selections.newest_anchor().head();
15630
15631        let Some((buffer, buffer_position)) =
15632            self.buffer.read(cx).text_anchor_for_position(position, cx)
15633        else {
15634            return;
15635        };
15636
15637        let project = self.project.clone();
15638
15639        cx.spawn_in(window, async move |_, cx| {
15640            let result = find_file(&buffer, project, buffer_position, cx).await;
15641
15642            if let Some((_, path)) = result {
15643                workspace
15644                    .update_in(cx, |workspace, window, cx| {
15645                        workspace.open_resolved_path(path, window, cx)
15646                    })?
15647                    .await?;
15648            }
15649            anyhow::Ok(())
15650        })
15651        .detach();
15652    }
15653
15654    pub(crate) fn navigate_to_hover_links(
15655        &mut self,
15656        kind: Option<GotoDefinitionKind>,
15657        mut definitions: Vec<HoverLink>,
15658        split: bool,
15659        window: &mut Window,
15660        cx: &mut Context<Editor>,
15661    ) -> Task<Result<Navigated>> {
15662        // If there is one definition, just open it directly
15663        if definitions.len() == 1 {
15664            let definition = definitions.pop().unwrap();
15665
15666            enum TargetTaskResult {
15667                Location(Option<Location>),
15668                AlreadyNavigated,
15669            }
15670
15671            let target_task = match definition {
15672                HoverLink::Text(link) => {
15673                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
15674                }
15675                HoverLink::InlayHint(lsp_location, server_id) => {
15676                    let computation =
15677                        self.compute_target_location(lsp_location, server_id, window, cx);
15678                    cx.background_spawn(async move {
15679                        let location = computation.await?;
15680                        Ok(TargetTaskResult::Location(location))
15681                    })
15682                }
15683                HoverLink::Url(url) => {
15684                    cx.open_url(&url);
15685                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15686                }
15687                HoverLink::File(path) => {
15688                    if let Some(workspace) = self.workspace() {
15689                        cx.spawn_in(window, async move |_, cx| {
15690                            workspace
15691                                .update_in(cx, |workspace, window, cx| {
15692                                    workspace.open_resolved_path(path, window, cx)
15693                                })?
15694                                .await
15695                                .map(|_| TargetTaskResult::AlreadyNavigated)
15696                        })
15697                    } else {
15698                        Task::ready(Ok(TargetTaskResult::Location(None)))
15699                    }
15700                }
15701            };
15702            cx.spawn_in(window, async move |editor, cx| {
15703                let target = match target_task.await.context("target resolution task")? {
15704                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15705                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15706                    TargetTaskResult::Location(Some(target)) => target,
15707                };
15708
15709                editor.update_in(cx, |editor, window, cx| {
15710                    let Some(workspace) = editor.workspace() else {
15711                        return Navigated::No;
15712                    };
15713                    let pane = workspace.read(cx).active_pane().clone();
15714
15715                    let range = target.range.to_point(target.buffer.read(cx));
15716                    let range = editor.range_for_match(&range);
15717                    let range = collapse_multiline_range(range);
15718
15719                    if !split
15720                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15721                    {
15722                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15723                    } else {
15724                        window.defer(cx, move |window, cx| {
15725                            let target_editor: Entity<Self> =
15726                                workspace.update(cx, |workspace, cx| {
15727                                    let pane = if split {
15728                                        workspace.adjacent_pane(window, cx)
15729                                    } else {
15730                                        workspace.active_pane().clone()
15731                                    };
15732
15733                                    workspace.open_project_item(
15734                                        pane,
15735                                        target.buffer.clone(),
15736                                        true,
15737                                        true,
15738                                        window,
15739                                        cx,
15740                                    )
15741                                });
15742                            target_editor.update(cx, |target_editor, cx| {
15743                                // When selecting a definition in a different buffer, disable the nav history
15744                                // to avoid creating a history entry at the previous cursor location.
15745                                pane.update(cx, |pane, _| pane.disable_history());
15746                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15747                                pane.update(cx, |pane, _| pane.enable_history());
15748                            });
15749                        });
15750                    }
15751                    Navigated::Yes
15752                })
15753            })
15754        } else if !definitions.is_empty() {
15755            cx.spawn_in(window, async move |editor, cx| {
15756                let (title, location_tasks, workspace) = editor
15757                    .update_in(cx, |editor, window, cx| {
15758                        let tab_kind = match kind {
15759                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15760                            _ => "Definitions",
15761                        };
15762                        let title = definitions
15763                            .iter()
15764                            .find_map(|definition| match definition {
15765                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15766                                    let buffer = origin.buffer.read(cx);
15767                                    format!(
15768                                        "{} for {}",
15769                                        tab_kind,
15770                                        buffer
15771                                            .text_for_range(origin.range.clone())
15772                                            .collect::<String>()
15773                                    )
15774                                }),
15775                                HoverLink::InlayHint(_, _) => None,
15776                                HoverLink::Url(_) => None,
15777                                HoverLink::File(_) => None,
15778                            })
15779                            .unwrap_or(tab_kind.to_string());
15780                        let location_tasks = definitions
15781                            .into_iter()
15782                            .map(|definition| match definition {
15783                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15784                                HoverLink::InlayHint(lsp_location, server_id) => editor
15785                                    .compute_target_location(lsp_location, server_id, window, cx),
15786                                HoverLink::Url(_) => Task::ready(Ok(None)),
15787                                HoverLink::File(_) => Task::ready(Ok(None)),
15788                            })
15789                            .collect::<Vec<_>>();
15790                        (title, location_tasks, editor.workspace().clone())
15791                    })
15792                    .context("location tasks preparation")?;
15793
15794                let locations: Vec<Location> = future::join_all(location_tasks)
15795                    .await
15796                    .into_iter()
15797                    .filter_map(|location| location.transpose())
15798                    .collect::<Result<_>>()
15799                    .context("location tasks")?;
15800
15801                if locations.is_empty() {
15802                    return Ok(Navigated::No);
15803                }
15804
15805                let Some(workspace) = workspace else {
15806                    return Ok(Navigated::No);
15807                };
15808
15809                let opened = workspace
15810                    .update_in(cx, |workspace, window, cx| {
15811                        Self::open_locations_in_multibuffer(
15812                            workspace,
15813                            locations,
15814                            title,
15815                            split,
15816                            MultibufferSelectionMode::First,
15817                            window,
15818                            cx,
15819                        )
15820                    })
15821                    .ok();
15822
15823                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15824            })
15825        } else {
15826            Task::ready(Ok(Navigated::No))
15827        }
15828    }
15829
15830    fn compute_target_location(
15831        &self,
15832        lsp_location: lsp::Location,
15833        server_id: LanguageServerId,
15834        window: &mut Window,
15835        cx: &mut Context<Self>,
15836    ) -> Task<anyhow::Result<Option<Location>>> {
15837        let Some(project) = self.project.clone() else {
15838            return Task::ready(Ok(None));
15839        };
15840
15841        cx.spawn_in(window, async move |editor, cx| {
15842            let location_task = editor.update(cx, |_, cx| {
15843                project.update(cx, |project, cx| {
15844                    let language_server_name = project
15845                        .language_server_statuses(cx)
15846                        .find(|(id, _)| server_id == *id)
15847                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15848                    language_server_name.map(|language_server_name| {
15849                        project.open_local_buffer_via_lsp(
15850                            lsp_location.uri.clone(),
15851                            server_id,
15852                            language_server_name,
15853                            cx,
15854                        )
15855                    })
15856                })
15857            })?;
15858            let location = match location_task {
15859                Some(task) => Some({
15860                    let target_buffer_handle = task.await.context("open local buffer")?;
15861                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15862                        let target_start = target_buffer
15863                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15864                        let target_end = target_buffer
15865                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15866                        target_buffer.anchor_after(target_start)
15867                            ..target_buffer.anchor_before(target_end)
15868                    })?;
15869                    Location {
15870                        buffer: target_buffer_handle,
15871                        range,
15872                    }
15873                }),
15874                None => None,
15875            };
15876            Ok(location)
15877        })
15878    }
15879
15880    pub fn find_all_references(
15881        &mut self,
15882        _: &FindAllReferences,
15883        window: &mut Window,
15884        cx: &mut Context<Self>,
15885    ) -> Option<Task<Result<Navigated>>> {
15886        let selection = self.selections.newest::<usize>(cx);
15887        let multi_buffer = self.buffer.read(cx);
15888        let head = selection.head();
15889
15890        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15891        let head_anchor = multi_buffer_snapshot.anchor_at(
15892            head,
15893            if head < selection.tail() {
15894                Bias::Right
15895            } else {
15896                Bias::Left
15897            },
15898        );
15899
15900        match self
15901            .find_all_references_task_sources
15902            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15903        {
15904            Ok(_) => {
15905                log::info!(
15906                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15907                );
15908                return None;
15909            }
15910            Err(i) => {
15911                self.find_all_references_task_sources.insert(i, head_anchor);
15912            }
15913        }
15914
15915        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15916        let workspace = self.workspace()?;
15917        let project = workspace.read(cx).project().clone();
15918        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15919        Some(cx.spawn_in(window, async move |editor, cx| {
15920            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15921                if let Ok(i) = editor
15922                    .find_all_references_task_sources
15923                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15924                {
15925                    editor.find_all_references_task_sources.remove(i);
15926                }
15927            });
15928
15929            let locations = references.await?;
15930            if locations.is_empty() {
15931                return anyhow::Ok(Navigated::No);
15932            }
15933
15934            workspace.update_in(cx, |workspace, window, cx| {
15935                let title = locations
15936                    .first()
15937                    .as_ref()
15938                    .map(|location| {
15939                        let buffer = location.buffer.read(cx);
15940                        format!(
15941                            "References to `{}`",
15942                            buffer
15943                                .text_for_range(location.range.clone())
15944                                .collect::<String>()
15945                        )
15946                    })
15947                    .unwrap();
15948                Self::open_locations_in_multibuffer(
15949                    workspace,
15950                    locations,
15951                    title,
15952                    false,
15953                    MultibufferSelectionMode::First,
15954                    window,
15955                    cx,
15956                );
15957                Navigated::Yes
15958            })
15959        }))
15960    }
15961
15962    /// Opens a multibuffer with the given project locations in it
15963    pub fn open_locations_in_multibuffer(
15964        workspace: &mut Workspace,
15965        mut locations: Vec<Location>,
15966        title: String,
15967        split: bool,
15968        multibuffer_selection_mode: MultibufferSelectionMode,
15969        window: &mut Window,
15970        cx: &mut Context<Workspace>,
15971    ) {
15972        if locations.is_empty() {
15973            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
15974            return;
15975        }
15976
15977        // If there are multiple definitions, open them in a multibuffer
15978        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15979        let mut locations = locations.into_iter().peekable();
15980        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15981        let capability = workspace.project().read(cx).capability();
15982
15983        let excerpt_buffer = cx.new(|cx| {
15984            let mut multibuffer = MultiBuffer::new(capability);
15985            while let Some(location) = locations.next() {
15986                let buffer = location.buffer.read(cx);
15987                let mut ranges_for_buffer = Vec::new();
15988                let range = location.range.to_point(buffer);
15989                ranges_for_buffer.push(range.clone());
15990
15991                while let Some(next_location) = locations.peek() {
15992                    if next_location.buffer == location.buffer {
15993                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15994                        locations.next();
15995                    } else {
15996                        break;
15997                    }
15998                }
15999
16000                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16001                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16002                    PathKey::for_buffer(&location.buffer, cx),
16003                    location.buffer.clone(),
16004                    ranges_for_buffer,
16005                    DEFAULT_MULTIBUFFER_CONTEXT,
16006                    cx,
16007                );
16008                ranges.extend(new_ranges)
16009            }
16010
16011            multibuffer.with_title(title)
16012        });
16013
16014        let editor = cx.new(|cx| {
16015            Editor::for_multibuffer(
16016                excerpt_buffer,
16017                Some(workspace.project().clone()),
16018                window,
16019                cx,
16020            )
16021        });
16022        editor.update(cx, |editor, cx| {
16023            match multibuffer_selection_mode {
16024                MultibufferSelectionMode::First => {
16025                    if let Some(first_range) = ranges.first() {
16026                        editor.change_selections(
16027                            SelectionEffects::no_scroll(),
16028                            window,
16029                            cx,
16030                            |selections| {
16031                                selections.clear_disjoint();
16032                                selections
16033                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16034                            },
16035                        );
16036                    }
16037                    editor.highlight_background::<Self>(
16038                        &ranges,
16039                        |theme| theme.colors().editor_highlighted_line_background,
16040                        cx,
16041                    );
16042                }
16043                MultibufferSelectionMode::All => {
16044                    editor.change_selections(
16045                        SelectionEffects::no_scroll(),
16046                        window,
16047                        cx,
16048                        |selections| {
16049                            selections.clear_disjoint();
16050                            selections.select_anchor_ranges(ranges);
16051                        },
16052                    );
16053                }
16054            }
16055            editor.register_buffers_with_language_servers(cx);
16056        });
16057
16058        let item = Box::new(editor);
16059        let item_id = item.item_id();
16060
16061        if split {
16062            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
16063        } else {
16064            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16065                let (preview_item_id, preview_item_idx) =
16066                    workspace.active_pane().read_with(cx, |pane, _| {
16067                        (pane.preview_item_id(), pane.preview_item_idx())
16068                    });
16069
16070                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
16071
16072                if let Some(preview_item_id) = preview_item_id {
16073                    workspace.active_pane().update(cx, |pane, cx| {
16074                        pane.remove_item(preview_item_id, false, false, window, cx);
16075                    });
16076                }
16077            } else {
16078                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
16079            }
16080        }
16081        workspace.active_pane().update(cx, |pane, cx| {
16082            pane.set_preview_item_id(Some(item_id), cx);
16083        });
16084    }
16085
16086    pub fn rename(
16087        &mut self,
16088        _: &Rename,
16089        window: &mut Window,
16090        cx: &mut Context<Self>,
16091    ) -> Option<Task<Result<()>>> {
16092        use language::ToOffset as _;
16093
16094        let provider = self.semantics_provider.clone()?;
16095        let selection = self.selections.newest_anchor().clone();
16096        let (cursor_buffer, cursor_buffer_position) = self
16097            .buffer
16098            .read(cx)
16099            .text_anchor_for_position(selection.head(), cx)?;
16100        let (tail_buffer, cursor_buffer_position_end) = self
16101            .buffer
16102            .read(cx)
16103            .text_anchor_for_position(selection.tail(), cx)?;
16104        if tail_buffer != cursor_buffer {
16105            return None;
16106        }
16107
16108        let snapshot = cursor_buffer.read(cx).snapshot();
16109        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16110        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16111        let prepare_rename = provider
16112            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16113            .unwrap_or_else(|| Task::ready(Ok(None)));
16114        drop(snapshot);
16115
16116        Some(cx.spawn_in(window, async move |this, cx| {
16117            let rename_range = if let Some(range) = prepare_rename.await? {
16118                Some(range)
16119            } else {
16120                this.update(cx, |this, cx| {
16121                    let buffer = this.buffer.read(cx).snapshot(cx);
16122                    let mut buffer_highlights = this
16123                        .document_highlights_for_position(selection.head(), &buffer)
16124                        .filter(|highlight| {
16125                            highlight.start.excerpt_id == selection.head().excerpt_id
16126                                && highlight.end.excerpt_id == selection.head().excerpt_id
16127                        });
16128                    buffer_highlights
16129                        .next()
16130                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16131                })?
16132            };
16133            if let Some(rename_range) = rename_range {
16134                this.update_in(cx, |this, window, cx| {
16135                    let snapshot = cursor_buffer.read(cx).snapshot();
16136                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16137                    let cursor_offset_in_rename_range =
16138                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16139                    let cursor_offset_in_rename_range_end =
16140                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16141
16142                    this.take_rename(false, window, cx);
16143                    let buffer = this.buffer.read(cx).read(cx);
16144                    let cursor_offset = selection.head().to_offset(&buffer);
16145                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16146                    let rename_end = rename_start + rename_buffer_range.len();
16147                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16148                    let mut old_highlight_id = None;
16149                    let old_name: Arc<str> = buffer
16150                        .chunks(rename_start..rename_end, true)
16151                        .map(|chunk| {
16152                            if old_highlight_id.is_none() {
16153                                old_highlight_id = chunk.syntax_highlight_id;
16154                            }
16155                            chunk.text
16156                        })
16157                        .collect::<String>()
16158                        .into();
16159
16160                    drop(buffer);
16161
16162                    // Position the selection in the rename editor so that it matches the current selection.
16163                    this.show_local_selections = false;
16164                    let rename_editor = cx.new(|cx| {
16165                        let mut editor = Editor::single_line(window, cx);
16166                        editor.buffer.update(cx, |buffer, cx| {
16167                            buffer.edit([(0..0, old_name.clone())], None, cx)
16168                        });
16169                        let rename_selection_range = match cursor_offset_in_rename_range
16170                            .cmp(&cursor_offset_in_rename_range_end)
16171                        {
16172                            Ordering::Equal => {
16173                                editor.select_all(&SelectAll, window, cx);
16174                                return editor;
16175                            }
16176                            Ordering::Less => {
16177                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16178                            }
16179                            Ordering::Greater => {
16180                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16181                            }
16182                        };
16183                        if rename_selection_range.end > old_name.len() {
16184                            editor.select_all(&SelectAll, window, cx);
16185                        } else {
16186                            editor.change_selections(Default::default(), window, cx, |s| {
16187                                s.select_ranges([rename_selection_range]);
16188                            });
16189                        }
16190                        editor
16191                    });
16192                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16193                        if e == &EditorEvent::Focused {
16194                            cx.emit(EditorEvent::FocusedIn)
16195                        }
16196                    })
16197                    .detach();
16198
16199                    let write_highlights =
16200                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16201                    let read_highlights =
16202                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16203                    let ranges = write_highlights
16204                        .iter()
16205                        .flat_map(|(_, ranges)| ranges.iter())
16206                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16207                        .cloned()
16208                        .collect();
16209
16210                    this.highlight_text::<Rename>(
16211                        ranges,
16212                        HighlightStyle {
16213                            fade_out: Some(0.6),
16214                            ..Default::default()
16215                        },
16216                        cx,
16217                    );
16218                    let rename_focus_handle = rename_editor.focus_handle(cx);
16219                    window.focus(&rename_focus_handle);
16220                    let block_id = this.insert_blocks(
16221                        [BlockProperties {
16222                            style: BlockStyle::Flex,
16223                            placement: BlockPlacement::Below(range.start),
16224                            height: Some(1),
16225                            render: Arc::new({
16226                                let rename_editor = rename_editor.clone();
16227                                move |cx: &mut BlockContext| {
16228                                    let mut text_style = cx.editor_style.text.clone();
16229                                    if let Some(highlight_style) = old_highlight_id
16230                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16231                                    {
16232                                        text_style = text_style.highlight(highlight_style);
16233                                    }
16234                                    div()
16235                                        .block_mouse_except_scroll()
16236                                        .pl(cx.anchor_x)
16237                                        .child(EditorElement::new(
16238                                            &rename_editor,
16239                                            EditorStyle {
16240                                                background: cx.theme().system().transparent,
16241                                                local_player: cx.editor_style.local_player,
16242                                                text: text_style,
16243                                                scrollbar_width: cx.editor_style.scrollbar_width,
16244                                                syntax: cx.editor_style.syntax.clone(),
16245                                                status: cx.editor_style.status.clone(),
16246                                                inlay_hints_style: HighlightStyle {
16247                                                    font_weight: Some(FontWeight::BOLD),
16248                                                    ..make_inlay_hints_style(cx.app)
16249                                                },
16250                                                inline_completion_styles: make_suggestion_styles(
16251                                                    cx.app,
16252                                                ),
16253                                                ..EditorStyle::default()
16254                                            },
16255                                        ))
16256                                        .into_any_element()
16257                                }
16258                            }),
16259                            priority: 0,
16260                        }],
16261                        Some(Autoscroll::fit()),
16262                        cx,
16263                    )[0];
16264                    this.pending_rename = Some(RenameState {
16265                        range,
16266                        old_name,
16267                        editor: rename_editor,
16268                        block_id,
16269                    });
16270                })?;
16271            }
16272
16273            Ok(())
16274        }))
16275    }
16276
16277    pub fn confirm_rename(
16278        &mut self,
16279        _: &ConfirmRename,
16280        window: &mut Window,
16281        cx: &mut Context<Self>,
16282    ) -> Option<Task<Result<()>>> {
16283        let rename = self.take_rename(false, window, cx)?;
16284        let workspace = self.workspace()?.downgrade();
16285        let (buffer, start) = self
16286            .buffer
16287            .read(cx)
16288            .text_anchor_for_position(rename.range.start, cx)?;
16289        let (end_buffer, _) = self
16290            .buffer
16291            .read(cx)
16292            .text_anchor_for_position(rename.range.end, cx)?;
16293        if buffer != end_buffer {
16294            return None;
16295        }
16296
16297        let old_name = rename.old_name;
16298        let new_name = rename.editor.read(cx).text(cx);
16299
16300        let rename = self.semantics_provider.as_ref()?.perform_rename(
16301            &buffer,
16302            start,
16303            new_name.clone(),
16304            cx,
16305        )?;
16306
16307        Some(cx.spawn_in(window, async move |editor, cx| {
16308            let project_transaction = rename.await?;
16309            Self::open_project_transaction(
16310                &editor,
16311                workspace,
16312                project_transaction,
16313                format!("Rename: {}{}", old_name, new_name),
16314                cx,
16315            )
16316            .await?;
16317
16318            editor.update(cx, |editor, cx| {
16319                editor.refresh_document_highlights(cx);
16320            })?;
16321            Ok(())
16322        }))
16323    }
16324
16325    fn take_rename(
16326        &mut self,
16327        moving_cursor: bool,
16328        window: &mut Window,
16329        cx: &mut Context<Self>,
16330    ) -> Option<RenameState> {
16331        let rename = self.pending_rename.take()?;
16332        if rename.editor.focus_handle(cx).is_focused(window) {
16333            window.focus(&self.focus_handle);
16334        }
16335
16336        self.remove_blocks(
16337            [rename.block_id].into_iter().collect(),
16338            Some(Autoscroll::fit()),
16339            cx,
16340        );
16341        self.clear_highlights::<Rename>(cx);
16342        self.show_local_selections = true;
16343
16344        if moving_cursor {
16345            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16346                editor.selections.newest::<usize>(cx).head()
16347            });
16348
16349            // Update the selection to match the position of the selection inside
16350            // the rename editor.
16351            let snapshot = self.buffer.read(cx).read(cx);
16352            let rename_range = rename.range.to_offset(&snapshot);
16353            let cursor_in_editor = snapshot
16354                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16355                .min(rename_range.end);
16356            drop(snapshot);
16357
16358            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16359                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16360            });
16361        } else {
16362            self.refresh_document_highlights(cx);
16363        }
16364
16365        Some(rename)
16366    }
16367
16368    pub fn pending_rename(&self) -> Option<&RenameState> {
16369        self.pending_rename.as_ref()
16370    }
16371
16372    fn format(
16373        &mut self,
16374        _: &Format,
16375        window: &mut Window,
16376        cx: &mut Context<Self>,
16377    ) -> Option<Task<Result<()>>> {
16378        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16379
16380        let project = match &self.project {
16381            Some(project) => project.clone(),
16382            None => return None,
16383        };
16384
16385        Some(self.perform_format(
16386            project,
16387            FormatTrigger::Manual,
16388            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16389            window,
16390            cx,
16391        ))
16392    }
16393
16394    fn format_selections(
16395        &mut self,
16396        _: &FormatSelections,
16397        window: &mut Window,
16398        cx: &mut Context<Self>,
16399    ) -> Option<Task<Result<()>>> {
16400        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16401
16402        let project = match &self.project {
16403            Some(project) => project.clone(),
16404            None => return None,
16405        };
16406
16407        let ranges = self
16408            .selections
16409            .all_adjusted(cx)
16410            .into_iter()
16411            .map(|selection| selection.range())
16412            .collect_vec();
16413
16414        Some(self.perform_format(
16415            project,
16416            FormatTrigger::Manual,
16417            FormatTarget::Ranges(ranges),
16418            window,
16419            cx,
16420        ))
16421    }
16422
16423    fn perform_format(
16424        &mut self,
16425        project: Entity<Project>,
16426        trigger: FormatTrigger,
16427        target: FormatTarget,
16428        window: &mut Window,
16429        cx: &mut Context<Self>,
16430    ) -> Task<Result<()>> {
16431        let buffer = self.buffer.clone();
16432        let (buffers, target) = match target {
16433            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16434            FormatTarget::Ranges(selection_ranges) => {
16435                let multi_buffer = buffer.read(cx);
16436                let snapshot = multi_buffer.read(cx);
16437                let mut buffers = HashSet::default();
16438                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16439                    BTreeMap::new();
16440                for selection_range in selection_ranges {
16441                    for (buffer, buffer_range, _) in
16442                        snapshot.range_to_buffer_ranges(selection_range)
16443                    {
16444                        let buffer_id = buffer.remote_id();
16445                        let start = buffer.anchor_before(buffer_range.start);
16446                        let end = buffer.anchor_after(buffer_range.end);
16447                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16448                        buffer_id_to_ranges
16449                            .entry(buffer_id)
16450                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16451                            .or_insert_with(|| vec![start..end]);
16452                    }
16453                }
16454                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16455            }
16456        };
16457
16458        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16459        let selections_prev = transaction_id_prev
16460            .and_then(|transaction_id_prev| {
16461                // default to selections as they were after the last edit, if we have them,
16462                // instead of how they are now.
16463                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16464                // will take you back to where you made the last edit, instead of staying where you scrolled
16465                self.selection_history
16466                    .transaction(transaction_id_prev)
16467                    .map(|t| t.0.clone())
16468            })
16469            .unwrap_or_else(|| {
16470                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
16471                self.selections.disjoint_anchors()
16472            });
16473
16474        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16475        let format = project.update(cx, |project, cx| {
16476            project.format(buffers, target, true, trigger, cx)
16477        });
16478
16479        cx.spawn_in(window, async move |editor, cx| {
16480            let transaction = futures::select_biased! {
16481                transaction = format.log_err().fuse() => transaction,
16482                () = timeout => {
16483                    log::warn!("timed out waiting for formatting");
16484                    None
16485                }
16486            };
16487
16488            buffer
16489                .update(cx, |buffer, cx| {
16490                    if let Some(transaction) = transaction {
16491                        if !buffer.is_singleton() {
16492                            buffer.push_transaction(&transaction.0, cx);
16493                        }
16494                    }
16495                    cx.notify();
16496                })
16497                .ok();
16498
16499            if let Some(transaction_id_now) =
16500                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16501            {
16502                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16503                if has_new_transaction {
16504                    _ = editor.update(cx, |editor, _| {
16505                        editor
16506                            .selection_history
16507                            .insert_transaction(transaction_id_now, selections_prev);
16508                    });
16509                }
16510            }
16511
16512            Ok(())
16513        })
16514    }
16515
16516    fn organize_imports(
16517        &mut self,
16518        _: &OrganizeImports,
16519        window: &mut Window,
16520        cx: &mut Context<Self>,
16521    ) -> Option<Task<Result<()>>> {
16522        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16523        let project = match &self.project {
16524            Some(project) => project.clone(),
16525            None => return None,
16526        };
16527        Some(self.perform_code_action_kind(
16528            project,
16529            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16530            window,
16531            cx,
16532        ))
16533    }
16534
16535    fn perform_code_action_kind(
16536        &mut self,
16537        project: Entity<Project>,
16538        kind: CodeActionKind,
16539        window: &mut Window,
16540        cx: &mut Context<Self>,
16541    ) -> Task<Result<()>> {
16542        let buffer = self.buffer.clone();
16543        let buffers = buffer.read(cx).all_buffers();
16544        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16545        let apply_action = project.update(cx, |project, cx| {
16546            project.apply_code_action_kind(buffers, kind, true, cx)
16547        });
16548        cx.spawn_in(window, async move |_, cx| {
16549            let transaction = futures::select_biased! {
16550                () = timeout => {
16551                    log::warn!("timed out waiting for executing code action");
16552                    None
16553                }
16554                transaction = apply_action.log_err().fuse() => transaction,
16555            };
16556            buffer
16557                .update(cx, |buffer, cx| {
16558                    // check if we need this
16559                    if let Some(transaction) = transaction {
16560                        if !buffer.is_singleton() {
16561                            buffer.push_transaction(&transaction.0, cx);
16562                        }
16563                    }
16564                    cx.notify();
16565                })
16566                .ok();
16567            Ok(())
16568        })
16569    }
16570
16571    pub fn restart_language_server(
16572        &mut self,
16573        _: &RestartLanguageServer,
16574        _: &mut Window,
16575        cx: &mut Context<Self>,
16576    ) {
16577        if let Some(project) = self.project.clone() {
16578            self.buffer.update(cx, |multi_buffer, cx| {
16579                project.update(cx, |project, cx| {
16580                    project.restart_language_servers_for_buffers(
16581                        multi_buffer.all_buffers().into_iter().collect(),
16582                        HashSet::default(),
16583                        cx,
16584                    );
16585                });
16586            })
16587        }
16588    }
16589
16590    pub fn stop_language_server(
16591        &mut self,
16592        _: &StopLanguageServer,
16593        _: &mut Window,
16594        cx: &mut Context<Self>,
16595    ) {
16596        if let Some(project) = self.project.clone() {
16597            self.buffer.update(cx, |multi_buffer, cx| {
16598                project.update(cx, |project, cx| {
16599                    project.stop_language_servers_for_buffers(
16600                        multi_buffer.all_buffers().into_iter().collect(),
16601                        HashSet::default(),
16602                        cx,
16603                    );
16604                    cx.emit(project::Event::RefreshInlayHints);
16605                });
16606            });
16607        }
16608    }
16609
16610    fn cancel_language_server_work(
16611        workspace: &mut Workspace,
16612        _: &actions::CancelLanguageServerWork,
16613        _: &mut Window,
16614        cx: &mut Context<Workspace>,
16615    ) {
16616        let project = workspace.project();
16617        let buffers = workspace
16618            .active_item(cx)
16619            .and_then(|item| item.act_as::<Editor>(cx))
16620            .map_or(HashSet::default(), |editor| {
16621                editor.read(cx).buffer.read(cx).all_buffers()
16622            });
16623        project.update(cx, |project, cx| {
16624            project.cancel_language_server_work_for_buffers(buffers, cx);
16625        });
16626    }
16627
16628    fn show_character_palette(
16629        &mut self,
16630        _: &ShowCharacterPalette,
16631        window: &mut Window,
16632        _: &mut Context<Self>,
16633    ) {
16634        window.show_character_palette();
16635    }
16636
16637    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16638        if !self.diagnostics_enabled() {
16639            return;
16640        }
16641
16642        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16643            let buffer = self.buffer.read(cx).snapshot(cx);
16644            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16645            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16646            let is_valid = buffer
16647                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16648                .any(|entry| {
16649                    entry.diagnostic.is_primary
16650                        && !entry.range.is_empty()
16651                        && entry.range.start == primary_range_start
16652                        && entry.diagnostic.message == active_diagnostics.active_message
16653                });
16654
16655            if !is_valid {
16656                self.dismiss_diagnostics(cx);
16657            }
16658        }
16659    }
16660
16661    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16662        match &self.active_diagnostics {
16663            ActiveDiagnostic::Group(group) => Some(group),
16664            _ => None,
16665        }
16666    }
16667
16668    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16669        if !self.diagnostics_enabled() {
16670            return;
16671        }
16672        self.dismiss_diagnostics(cx);
16673        self.active_diagnostics = ActiveDiagnostic::All;
16674    }
16675
16676    fn activate_diagnostics(
16677        &mut self,
16678        buffer_id: BufferId,
16679        diagnostic: DiagnosticEntry<usize>,
16680        window: &mut Window,
16681        cx: &mut Context<Self>,
16682    ) {
16683        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16684            return;
16685        }
16686        self.dismiss_diagnostics(cx);
16687        let snapshot = self.snapshot(window, cx);
16688        let buffer = self.buffer.read(cx).snapshot(cx);
16689        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16690            return;
16691        };
16692
16693        let diagnostic_group = buffer
16694            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16695            .collect::<Vec<_>>();
16696
16697        let blocks =
16698            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16699
16700        let blocks = self.display_map.update(cx, |display_map, cx| {
16701            display_map.insert_blocks(blocks, cx).into_iter().collect()
16702        });
16703        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16704            active_range: buffer.anchor_before(diagnostic.range.start)
16705                ..buffer.anchor_after(diagnostic.range.end),
16706            active_message: diagnostic.diagnostic.message.clone(),
16707            group_id: diagnostic.diagnostic.group_id,
16708            blocks,
16709        });
16710        cx.notify();
16711    }
16712
16713    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16714        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16715            return;
16716        };
16717
16718        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16719        if let ActiveDiagnostic::Group(group) = prev {
16720            self.display_map.update(cx, |display_map, cx| {
16721                display_map.remove_blocks(group.blocks, cx);
16722            });
16723            cx.notify();
16724        }
16725    }
16726
16727    /// Disable inline diagnostics rendering for this editor.
16728    pub fn disable_inline_diagnostics(&mut self) {
16729        self.inline_diagnostics_enabled = false;
16730        self.inline_diagnostics_update = Task::ready(());
16731        self.inline_diagnostics.clear();
16732    }
16733
16734    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16735        self.diagnostics_enabled = false;
16736        self.dismiss_diagnostics(cx);
16737        self.inline_diagnostics_update = Task::ready(());
16738        self.inline_diagnostics.clear();
16739    }
16740
16741    pub fn diagnostics_enabled(&self) -> bool {
16742        self.diagnostics_enabled && self.mode.is_full()
16743    }
16744
16745    pub fn inline_diagnostics_enabled(&self) -> bool {
16746        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16747    }
16748
16749    pub fn show_inline_diagnostics(&self) -> bool {
16750        self.show_inline_diagnostics
16751    }
16752
16753    pub fn toggle_inline_diagnostics(
16754        &mut self,
16755        _: &ToggleInlineDiagnostics,
16756        window: &mut Window,
16757        cx: &mut Context<Editor>,
16758    ) {
16759        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16760        self.refresh_inline_diagnostics(false, window, cx);
16761    }
16762
16763    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16764        self.diagnostics_max_severity = severity;
16765        self.display_map.update(cx, |display_map, _| {
16766            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16767        });
16768    }
16769
16770    pub fn toggle_diagnostics(
16771        &mut self,
16772        _: &ToggleDiagnostics,
16773        window: &mut Window,
16774        cx: &mut Context<Editor>,
16775    ) {
16776        if !self.diagnostics_enabled() {
16777            return;
16778        }
16779
16780        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16781            EditorSettings::get_global(cx)
16782                .diagnostics_max_severity
16783                .filter(|severity| severity != &DiagnosticSeverity::Off)
16784                .unwrap_or(DiagnosticSeverity::Hint)
16785        } else {
16786            DiagnosticSeverity::Off
16787        };
16788        self.set_max_diagnostics_severity(new_severity, cx);
16789        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16790            self.active_diagnostics = ActiveDiagnostic::None;
16791            self.inline_diagnostics_update = Task::ready(());
16792            self.inline_diagnostics.clear();
16793        } else {
16794            self.refresh_inline_diagnostics(false, window, cx);
16795        }
16796
16797        cx.notify();
16798    }
16799
16800    pub fn toggle_minimap(
16801        &mut self,
16802        _: &ToggleMinimap,
16803        window: &mut Window,
16804        cx: &mut Context<Editor>,
16805    ) {
16806        if self.supports_minimap(cx) {
16807            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16808        }
16809    }
16810
16811    fn refresh_inline_diagnostics(
16812        &mut self,
16813        debounce: bool,
16814        window: &mut Window,
16815        cx: &mut Context<Self>,
16816    ) {
16817        let max_severity = ProjectSettings::get_global(cx)
16818            .diagnostics
16819            .inline
16820            .max_severity
16821            .unwrap_or(self.diagnostics_max_severity);
16822
16823        if !self.inline_diagnostics_enabled()
16824            || !self.show_inline_diagnostics
16825            || max_severity == DiagnosticSeverity::Off
16826        {
16827            self.inline_diagnostics_update = Task::ready(());
16828            self.inline_diagnostics.clear();
16829            return;
16830        }
16831
16832        let debounce_ms = ProjectSettings::get_global(cx)
16833            .diagnostics
16834            .inline
16835            .update_debounce_ms;
16836        let debounce = if debounce && debounce_ms > 0 {
16837            Some(Duration::from_millis(debounce_ms))
16838        } else {
16839            None
16840        };
16841        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16842            if let Some(debounce) = debounce {
16843                cx.background_executor().timer(debounce).await;
16844            }
16845            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16846                editor
16847                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16848                    .ok()
16849            }) else {
16850                return;
16851            };
16852
16853            let new_inline_diagnostics = cx
16854                .background_spawn(async move {
16855                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16856                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16857                        let message = diagnostic_entry
16858                            .diagnostic
16859                            .message
16860                            .split_once('\n')
16861                            .map(|(line, _)| line)
16862                            .map(SharedString::new)
16863                            .unwrap_or_else(|| {
16864                                SharedString::from(diagnostic_entry.diagnostic.message)
16865                            });
16866                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16867                        let (Ok(i) | Err(i)) = inline_diagnostics
16868                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16869                        inline_diagnostics.insert(
16870                            i,
16871                            (
16872                                start_anchor,
16873                                InlineDiagnostic {
16874                                    message,
16875                                    group_id: diagnostic_entry.diagnostic.group_id,
16876                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16877                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16878                                    severity: diagnostic_entry.diagnostic.severity,
16879                                },
16880                            ),
16881                        );
16882                    }
16883                    inline_diagnostics
16884                })
16885                .await;
16886
16887            editor
16888                .update(cx, |editor, cx| {
16889                    editor.inline_diagnostics = new_inline_diagnostics;
16890                    cx.notify();
16891                })
16892                .ok();
16893        });
16894    }
16895
16896    fn pull_diagnostics(
16897        &mut self,
16898        buffer_id: Option<BufferId>,
16899        window: &Window,
16900        cx: &mut Context<Self>,
16901    ) -> Option<()> {
16902        if !self.mode().is_full() {
16903            return None;
16904        }
16905        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16906            .diagnostics
16907            .lsp_pull_diagnostics;
16908        if !pull_diagnostics_settings.enabled {
16909            return None;
16910        }
16911        let project = self.project.as_ref()?.downgrade();
16912        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16913        let mut buffers = self.buffer.read(cx).all_buffers();
16914        if let Some(buffer_id) = buffer_id {
16915            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16916        }
16917
16918        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16919            cx.background_executor().timer(debounce).await;
16920
16921            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16922                buffers
16923                    .into_iter()
16924                    .filter_map(|buffer| {
16925                        project
16926                            .update(cx, |project, cx| {
16927                                project.lsp_store().update(cx, |lsp_store, cx| {
16928                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
16929                                })
16930                            })
16931                            .ok()
16932                    })
16933                    .collect::<FuturesUnordered<_>>()
16934            }) else {
16935                return;
16936            };
16937
16938            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16939                match pull_task {
16940                    Ok(()) => {
16941                        if editor
16942                            .update_in(cx, |editor, window, cx| {
16943                                editor.update_diagnostics_state(window, cx);
16944                            })
16945                            .is_err()
16946                        {
16947                            return;
16948                        }
16949                    }
16950                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16951                }
16952            }
16953        });
16954
16955        Some(())
16956    }
16957
16958    pub fn set_selections_from_remote(
16959        &mut self,
16960        selections: Vec<Selection<Anchor>>,
16961        pending_selection: Option<Selection<Anchor>>,
16962        window: &mut Window,
16963        cx: &mut Context<Self>,
16964    ) {
16965        let old_cursor_position = self.selections.newest_anchor().head();
16966        self.selections.change_with(cx, |s| {
16967            s.select_anchors(selections);
16968            if let Some(pending_selection) = pending_selection {
16969                s.set_pending(pending_selection, SelectMode::Character);
16970            } else {
16971                s.clear_pending();
16972            }
16973        });
16974        self.selections_did_change(
16975            false,
16976            &old_cursor_position,
16977            SelectionEffects::default(),
16978            window,
16979            cx,
16980        );
16981    }
16982
16983    pub fn transact(
16984        &mut self,
16985        window: &mut Window,
16986        cx: &mut Context<Self>,
16987        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16988    ) -> Option<TransactionId> {
16989        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16990            this.start_transaction_at(Instant::now(), window, cx);
16991            update(this, window, cx);
16992            this.end_transaction_at(Instant::now(), cx)
16993        })
16994    }
16995
16996    pub fn start_transaction_at(
16997        &mut self,
16998        now: Instant,
16999        window: &mut Window,
17000        cx: &mut Context<Self>,
17001    ) -> Option<TransactionId> {
17002        self.end_selection(window, cx);
17003        if let Some(tx_id) = self
17004            .buffer
17005            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17006        {
17007            self.selection_history
17008                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17009            cx.emit(EditorEvent::TransactionBegun {
17010                transaction_id: tx_id,
17011            });
17012            Some(tx_id)
17013        } else {
17014            None
17015        }
17016    }
17017
17018    pub fn end_transaction_at(
17019        &mut self,
17020        now: Instant,
17021        cx: &mut Context<Self>,
17022    ) -> Option<TransactionId> {
17023        if let Some(transaction_id) = self
17024            .buffer
17025            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17026        {
17027            if let Some((_, end_selections)) =
17028                self.selection_history.transaction_mut(transaction_id)
17029            {
17030                *end_selections = Some(self.selections.disjoint_anchors());
17031            } else {
17032                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17033            }
17034
17035            cx.emit(EditorEvent::Edited { transaction_id });
17036            Some(transaction_id)
17037        } else {
17038            None
17039        }
17040    }
17041
17042    pub fn modify_transaction_selection_history(
17043        &mut self,
17044        transaction_id: TransactionId,
17045        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17046    ) -> bool {
17047        self.selection_history
17048            .transaction_mut(transaction_id)
17049            .map(modify)
17050            .is_some()
17051    }
17052
17053    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17054        if self.selection_mark_mode {
17055            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17056                s.move_with(|_, sel| {
17057                    sel.collapse_to(sel.head(), SelectionGoal::None);
17058                });
17059            })
17060        }
17061        self.selection_mark_mode = true;
17062        cx.notify();
17063    }
17064
17065    pub fn swap_selection_ends(
17066        &mut self,
17067        _: &actions::SwapSelectionEnds,
17068        window: &mut Window,
17069        cx: &mut Context<Self>,
17070    ) {
17071        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17072            s.move_with(|_, sel| {
17073                if sel.start != sel.end {
17074                    sel.reversed = !sel.reversed
17075                }
17076            });
17077        });
17078        self.request_autoscroll(Autoscroll::newest(), cx);
17079        cx.notify();
17080    }
17081
17082    pub fn toggle_focus(
17083        workspace: &mut Workspace,
17084        _: &actions::ToggleFocus,
17085        window: &mut Window,
17086        cx: &mut Context<Workspace>,
17087    ) {
17088        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17089            return;
17090        };
17091        workspace.activate_item(&item, true, true, window, cx);
17092    }
17093
17094    pub fn toggle_fold(
17095        &mut self,
17096        _: &actions::ToggleFold,
17097        window: &mut Window,
17098        cx: &mut Context<Self>,
17099    ) {
17100        if self.is_singleton(cx) {
17101            let selection = self.selections.newest::<Point>(cx);
17102
17103            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17104            let range = if selection.is_empty() {
17105                let point = selection.head().to_display_point(&display_map);
17106                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17107                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17108                    .to_point(&display_map);
17109                start..end
17110            } else {
17111                selection.range()
17112            };
17113            if display_map.folds_in_range(range).next().is_some() {
17114                self.unfold_lines(&Default::default(), window, cx)
17115            } else {
17116                self.fold(&Default::default(), window, cx)
17117            }
17118        } else {
17119            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17120            let buffer_ids: HashSet<_> = self
17121                .selections
17122                .disjoint_anchor_ranges()
17123                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17124                .collect();
17125
17126            let should_unfold = buffer_ids
17127                .iter()
17128                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17129
17130            for buffer_id in buffer_ids {
17131                if should_unfold {
17132                    self.unfold_buffer(buffer_id, cx);
17133                } else {
17134                    self.fold_buffer(buffer_id, cx);
17135                }
17136            }
17137        }
17138    }
17139
17140    pub fn toggle_fold_recursive(
17141        &mut self,
17142        _: &actions::ToggleFoldRecursive,
17143        window: &mut Window,
17144        cx: &mut Context<Self>,
17145    ) {
17146        let selection = self.selections.newest::<Point>(cx);
17147
17148        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17149        let range = if selection.is_empty() {
17150            let point = selection.head().to_display_point(&display_map);
17151            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17152            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17153                .to_point(&display_map);
17154            start..end
17155        } else {
17156            selection.range()
17157        };
17158        if display_map.folds_in_range(range).next().is_some() {
17159            self.unfold_recursive(&Default::default(), window, cx)
17160        } else {
17161            self.fold_recursive(&Default::default(), window, cx)
17162        }
17163    }
17164
17165    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17166        if self.is_singleton(cx) {
17167            let mut to_fold = Vec::new();
17168            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17169            let selections = self.selections.all_adjusted(cx);
17170
17171            for selection in selections {
17172                let range = selection.range().sorted();
17173                let buffer_start_row = range.start.row;
17174
17175                if range.start.row != range.end.row {
17176                    let mut found = false;
17177                    let mut row = range.start.row;
17178                    while row <= range.end.row {
17179                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17180                        {
17181                            found = true;
17182                            row = crease.range().end.row + 1;
17183                            to_fold.push(crease);
17184                        } else {
17185                            row += 1
17186                        }
17187                    }
17188                    if found {
17189                        continue;
17190                    }
17191                }
17192
17193                for row in (0..=range.start.row).rev() {
17194                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17195                        if crease.range().end.row >= buffer_start_row {
17196                            to_fold.push(crease);
17197                            if row <= range.start.row {
17198                                break;
17199                            }
17200                        }
17201                    }
17202                }
17203            }
17204
17205            self.fold_creases(to_fold, true, window, cx);
17206        } else {
17207            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17208            let buffer_ids = self
17209                .selections
17210                .disjoint_anchor_ranges()
17211                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17212                .collect::<HashSet<_>>();
17213            for buffer_id in buffer_ids {
17214                self.fold_buffer(buffer_id, cx);
17215            }
17216        }
17217    }
17218
17219    pub fn toggle_fold_all(
17220        &mut self,
17221        _: &actions::ToggleFoldAll,
17222        window: &mut Window,
17223        cx: &mut Context<Self>,
17224    ) {
17225        if self.buffer.read(cx).is_singleton() {
17226            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17227            let has_folds = display_map
17228                .folds_in_range(0..display_map.buffer_snapshot.len())
17229                .next()
17230                .is_some();
17231
17232            if has_folds {
17233                self.unfold_all(&actions::UnfoldAll, window, cx);
17234            } else {
17235                self.fold_all(&actions::FoldAll, window, cx);
17236            }
17237        } else {
17238            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17239            let should_unfold = buffer_ids
17240                .iter()
17241                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17242
17243            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17244                editor
17245                    .update_in(cx, |editor, _, cx| {
17246                        for buffer_id in buffer_ids {
17247                            if should_unfold {
17248                                editor.unfold_buffer(buffer_id, cx);
17249                            } else {
17250                                editor.fold_buffer(buffer_id, cx);
17251                            }
17252                        }
17253                    })
17254                    .ok();
17255            });
17256        }
17257    }
17258
17259    fn fold_at_level(
17260        &mut self,
17261        fold_at: &FoldAtLevel,
17262        window: &mut Window,
17263        cx: &mut Context<Self>,
17264    ) {
17265        if !self.buffer.read(cx).is_singleton() {
17266            return;
17267        }
17268
17269        let fold_at_level = fold_at.0;
17270        let snapshot = self.buffer.read(cx).snapshot(cx);
17271        let mut to_fold = Vec::new();
17272        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17273
17274        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17275            while start_row < end_row {
17276                match self
17277                    .snapshot(window, cx)
17278                    .crease_for_buffer_row(MultiBufferRow(start_row))
17279                {
17280                    Some(crease) => {
17281                        let nested_start_row = crease.range().start.row + 1;
17282                        let nested_end_row = crease.range().end.row;
17283
17284                        if current_level < fold_at_level {
17285                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17286                        } else if current_level == fold_at_level {
17287                            to_fold.push(crease);
17288                        }
17289
17290                        start_row = nested_end_row + 1;
17291                    }
17292                    None => start_row += 1,
17293                }
17294            }
17295        }
17296
17297        self.fold_creases(to_fold, true, window, cx);
17298    }
17299
17300    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17301        if self.buffer.read(cx).is_singleton() {
17302            let mut fold_ranges = Vec::new();
17303            let snapshot = self.buffer.read(cx).snapshot(cx);
17304
17305            for row in 0..snapshot.max_row().0 {
17306                if let Some(foldable_range) = self
17307                    .snapshot(window, cx)
17308                    .crease_for_buffer_row(MultiBufferRow(row))
17309                {
17310                    fold_ranges.push(foldable_range);
17311                }
17312            }
17313
17314            self.fold_creases(fold_ranges, true, window, cx);
17315        } else {
17316            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17317                editor
17318                    .update_in(cx, |editor, _, cx| {
17319                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17320                            editor.fold_buffer(buffer_id, cx);
17321                        }
17322                    })
17323                    .ok();
17324            });
17325        }
17326    }
17327
17328    pub fn fold_function_bodies(
17329        &mut self,
17330        _: &actions::FoldFunctionBodies,
17331        window: &mut Window,
17332        cx: &mut Context<Self>,
17333    ) {
17334        let snapshot = self.buffer.read(cx).snapshot(cx);
17335
17336        let ranges = snapshot
17337            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17338            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17339            .collect::<Vec<_>>();
17340
17341        let creases = ranges
17342            .into_iter()
17343            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17344            .collect();
17345
17346        self.fold_creases(creases, true, window, cx);
17347    }
17348
17349    pub fn fold_recursive(
17350        &mut self,
17351        _: &actions::FoldRecursive,
17352        window: &mut Window,
17353        cx: &mut Context<Self>,
17354    ) {
17355        let mut to_fold = Vec::new();
17356        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17357        let selections = self.selections.all_adjusted(cx);
17358
17359        for selection in selections {
17360            let range = selection.range().sorted();
17361            let buffer_start_row = range.start.row;
17362
17363            if range.start.row != range.end.row {
17364                let mut found = false;
17365                for row in range.start.row..=range.end.row {
17366                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17367                        found = true;
17368                        to_fold.push(crease);
17369                    }
17370                }
17371                if found {
17372                    continue;
17373                }
17374            }
17375
17376            for row in (0..=range.start.row).rev() {
17377                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17378                    if crease.range().end.row >= buffer_start_row {
17379                        to_fold.push(crease);
17380                    } else {
17381                        break;
17382                    }
17383                }
17384            }
17385        }
17386
17387        self.fold_creases(to_fold, true, window, cx);
17388    }
17389
17390    pub fn fold_at(
17391        &mut self,
17392        buffer_row: MultiBufferRow,
17393        window: &mut Window,
17394        cx: &mut Context<Self>,
17395    ) {
17396        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17397
17398        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17399            let autoscroll = self
17400                .selections
17401                .all::<Point>(cx)
17402                .iter()
17403                .any(|selection| crease.range().overlaps(&selection.range()));
17404
17405            self.fold_creases(vec![crease], autoscroll, window, cx);
17406        }
17407    }
17408
17409    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17410        if self.is_singleton(cx) {
17411            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17412            let buffer = &display_map.buffer_snapshot;
17413            let selections = self.selections.all::<Point>(cx);
17414            let ranges = selections
17415                .iter()
17416                .map(|s| {
17417                    let range = s.display_range(&display_map).sorted();
17418                    let mut start = range.start.to_point(&display_map);
17419                    let mut end = range.end.to_point(&display_map);
17420                    start.column = 0;
17421                    end.column = buffer.line_len(MultiBufferRow(end.row));
17422                    start..end
17423                })
17424                .collect::<Vec<_>>();
17425
17426            self.unfold_ranges(&ranges, true, true, cx);
17427        } else {
17428            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17429            let buffer_ids = self
17430                .selections
17431                .disjoint_anchor_ranges()
17432                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17433                .collect::<HashSet<_>>();
17434            for buffer_id in buffer_ids {
17435                self.unfold_buffer(buffer_id, cx);
17436            }
17437        }
17438    }
17439
17440    pub fn unfold_recursive(
17441        &mut self,
17442        _: &UnfoldRecursive,
17443        _window: &mut Window,
17444        cx: &mut Context<Self>,
17445    ) {
17446        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17447        let selections = self.selections.all::<Point>(cx);
17448        let ranges = selections
17449            .iter()
17450            .map(|s| {
17451                let mut range = s.display_range(&display_map).sorted();
17452                *range.start.column_mut() = 0;
17453                *range.end.column_mut() = display_map.line_len(range.end.row());
17454                let start = range.start.to_point(&display_map);
17455                let end = range.end.to_point(&display_map);
17456                start..end
17457            })
17458            .collect::<Vec<_>>();
17459
17460        self.unfold_ranges(&ranges, true, true, cx);
17461    }
17462
17463    pub fn unfold_at(
17464        &mut self,
17465        buffer_row: MultiBufferRow,
17466        _window: &mut Window,
17467        cx: &mut Context<Self>,
17468    ) {
17469        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17470
17471        let intersection_range = Point::new(buffer_row.0, 0)
17472            ..Point::new(
17473                buffer_row.0,
17474                display_map.buffer_snapshot.line_len(buffer_row),
17475            );
17476
17477        let autoscroll = self
17478            .selections
17479            .all::<Point>(cx)
17480            .iter()
17481            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17482
17483        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17484    }
17485
17486    pub fn unfold_all(
17487        &mut self,
17488        _: &actions::UnfoldAll,
17489        _window: &mut Window,
17490        cx: &mut Context<Self>,
17491    ) {
17492        if self.buffer.read(cx).is_singleton() {
17493            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17494            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17495        } else {
17496            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17497                editor
17498                    .update(cx, |editor, cx| {
17499                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17500                            editor.unfold_buffer(buffer_id, cx);
17501                        }
17502                    })
17503                    .ok();
17504            });
17505        }
17506    }
17507
17508    pub fn fold_selected_ranges(
17509        &mut self,
17510        _: &FoldSelectedRanges,
17511        window: &mut Window,
17512        cx: &mut Context<Self>,
17513    ) {
17514        let selections = self.selections.all_adjusted(cx);
17515        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17516        let ranges = selections
17517            .into_iter()
17518            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17519            .collect::<Vec<_>>();
17520        self.fold_creases(ranges, true, window, cx);
17521    }
17522
17523    pub fn fold_ranges<T: ToOffset + Clone>(
17524        &mut self,
17525        ranges: Vec<Range<T>>,
17526        auto_scroll: bool,
17527        window: &mut Window,
17528        cx: &mut Context<Self>,
17529    ) {
17530        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17531        let ranges = ranges
17532            .into_iter()
17533            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17534            .collect::<Vec<_>>();
17535        self.fold_creases(ranges, auto_scroll, window, cx);
17536    }
17537
17538    pub fn fold_creases<T: ToOffset + Clone>(
17539        &mut self,
17540        creases: Vec<Crease<T>>,
17541        auto_scroll: bool,
17542        _window: &mut Window,
17543        cx: &mut Context<Self>,
17544    ) {
17545        if creases.is_empty() {
17546            return;
17547        }
17548
17549        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17550
17551        if auto_scroll {
17552            self.request_autoscroll(Autoscroll::fit(), cx);
17553        }
17554
17555        cx.notify();
17556
17557        self.scrollbar_marker_state.dirty = true;
17558        self.folds_did_change(cx);
17559    }
17560
17561    /// Removes any folds whose ranges intersect any of the given ranges.
17562    pub fn unfold_ranges<T: ToOffset + Clone>(
17563        &mut self,
17564        ranges: &[Range<T>],
17565        inclusive: bool,
17566        auto_scroll: bool,
17567        cx: &mut Context<Self>,
17568    ) {
17569        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17570            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17571        });
17572        self.folds_did_change(cx);
17573    }
17574
17575    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17576        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17577            return;
17578        }
17579        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17580        self.display_map.update(cx, |display_map, cx| {
17581            display_map.fold_buffers([buffer_id], cx)
17582        });
17583        cx.emit(EditorEvent::BufferFoldToggled {
17584            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17585            folded: true,
17586        });
17587        cx.notify();
17588    }
17589
17590    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17591        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17592            return;
17593        }
17594        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17595        self.display_map.update(cx, |display_map, cx| {
17596            display_map.unfold_buffers([buffer_id], cx);
17597        });
17598        cx.emit(EditorEvent::BufferFoldToggled {
17599            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17600            folded: false,
17601        });
17602        cx.notify();
17603    }
17604
17605    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17606        self.display_map.read(cx).is_buffer_folded(buffer)
17607    }
17608
17609    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17610        self.display_map.read(cx).folded_buffers()
17611    }
17612
17613    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17614        self.display_map.update(cx, |display_map, cx| {
17615            display_map.disable_header_for_buffer(buffer_id, cx);
17616        });
17617        cx.notify();
17618    }
17619
17620    /// Removes any folds with the given ranges.
17621    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17622        &mut self,
17623        ranges: &[Range<T>],
17624        type_id: TypeId,
17625        auto_scroll: bool,
17626        cx: &mut Context<Self>,
17627    ) {
17628        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17629            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17630        });
17631        self.folds_did_change(cx);
17632    }
17633
17634    fn remove_folds_with<T: ToOffset + Clone>(
17635        &mut self,
17636        ranges: &[Range<T>],
17637        auto_scroll: bool,
17638        cx: &mut Context<Self>,
17639        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17640    ) {
17641        if ranges.is_empty() {
17642            return;
17643        }
17644
17645        let mut buffers_affected = HashSet::default();
17646        let multi_buffer = self.buffer().read(cx);
17647        for range in ranges {
17648            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17649                buffers_affected.insert(buffer.read(cx).remote_id());
17650            };
17651        }
17652
17653        self.display_map.update(cx, update);
17654
17655        if auto_scroll {
17656            self.request_autoscroll(Autoscroll::fit(), cx);
17657        }
17658
17659        cx.notify();
17660        self.scrollbar_marker_state.dirty = true;
17661        self.active_indent_guides_state.dirty = true;
17662    }
17663
17664    pub fn update_renderer_widths(
17665        &mut self,
17666        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17667        cx: &mut Context<Self>,
17668    ) -> bool {
17669        self.display_map
17670            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17671    }
17672
17673    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17674        self.display_map.read(cx).fold_placeholder.clone()
17675    }
17676
17677    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17678        self.buffer.update(cx, |buffer, cx| {
17679            buffer.set_all_diff_hunks_expanded(cx);
17680        });
17681    }
17682
17683    pub fn expand_all_diff_hunks(
17684        &mut self,
17685        _: &ExpandAllDiffHunks,
17686        _window: &mut Window,
17687        cx: &mut Context<Self>,
17688    ) {
17689        self.buffer.update(cx, |buffer, cx| {
17690            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17691        });
17692    }
17693
17694    pub fn toggle_selected_diff_hunks(
17695        &mut self,
17696        _: &ToggleSelectedDiffHunks,
17697        _window: &mut Window,
17698        cx: &mut Context<Self>,
17699    ) {
17700        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17701        self.toggle_diff_hunks_in_ranges(ranges, cx);
17702    }
17703
17704    pub fn diff_hunks_in_ranges<'a>(
17705        &'a self,
17706        ranges: &'a [Range<Anchor>],
17707        buffer: &'a MultiBufferSnapshot,
17708    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17709        ranges.iter().flat_map(move |range| {
17710            let end_excerpt_id = range.end.excerpt_id;
17711            let range = range.to_point(buffer);
17712            let mut peek_end = range.end;
17713            if range.end.row < buffer.max_row().0 {
17714                peek_end = Point::new(range.end.row + 1, 0);
17715            }
17716            buffer
17717                .diff_hunks_in_range(range.start..peek_end)
17718                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17719        })
17720    }
17721
17722    pub fn has_stageable_diff_hunks_in_ranges(
17723        &self,
17724        ranges: &[Range<Anchor>],
17725        snapshot: &MultiBufferSnapshot,
17726    ) -> bool {
17727        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17728        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17729    }
17730
17731    pub fn toggle_staged_selected_diff_hunks(
17732        &mut self,
17733        _: &::git::ToggleStaged,
17734        _: &mut Window,
17735        cx: &mut Context<Self>,
17736    ) {
17737        let snapshot = self.buffer.read(cx).snapshot(cx);
17738        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17739        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17740        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17741    }
17742
17743    pub fn set_render_diff_hunk_controls(
17744        &mut self,
17745        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17746        cx: &mut Context<Self>,
17747    ) {
17748        self.render_diff_hunk_controls = render_diff_hunk_controls;
17749        cx.notify();
17750    }
17751
17752    pub fn stage_and_next(
17753        &mut self,
17754        _: &::git::StageAndNext,
17755        window: &mut Window,
17756        cx: &mut Context<Self>,
17757    ) {
17758        self.do_stage_or_unstage_and_next(true, window, cx);
17759    }
17760
17761    pub fn unstage_and_next(
17762        &mut self,
17763        _: &::git::UnstageAndNext,
17764        window: &mut Window,
17765        cx: &mut Context<Self>,
17766    ) {
17767        self.do_stage_or_unstage_and_next(false, window, cx);
17768    }
17769
17770    pub fn stage_or_unstage_diff_hunks(
17771        &mut self,
17772        stage: bool,
17773        ranges: Vec<Range<Anchor>>,
17774        cx: &mut Context<Self>,
17775    ) {
17776        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17777        cx.spawn(async move |this, cx| {
17778            task.await?;
17779            this.update(cx, |this, cx| {
17780                let snapshot = this.buffer.read(cx).snapshot(cx);
17781                let chunk_by = this
17782                    .diff_hunks_in_ranges(&ranges, &snapshot)
17783                    .chunk_by(|hunk| hunk.buffer_id);
17784                for (buffer_id, hunks) in &chunk_by {
17785                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17786                }
17787            })
17788        })
17789        .detach_and_log_err(cx);
17790    }
17791
17792    fn save_buffers_for_ranges_if_needed(
17793        &mut self,
17794        ranges: &[Range<Anchor>],
17795        cx: &mut Context<Editor>,
17796    ) -> Task<Result<()>> {
17797        let multibuffer = self.buffer.read(cx);
17798        let snapshot = multibuffer.read(cx);
17799        let buffer_ids: HashSet<_> = ranges
17800            .iter()
17801            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17802            .collect();
17803        drop(snapshot);
17804
17805        let mut buffers = HashSet::default();
17806        for buffer_id in buffer_ids {
17807            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17808                let buffer = buffer_entity.read(cx);
17809                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17810                {
17811                    buffers.insert(buffer_entity);
17812                }
17813            }
17814        }
17815
17816        if let Some(project) = &self.project {
17817            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17818        } else {
17819            Task::ready(Ok(()))
17820        }
17821    }
17822
17823    fn do_stage_or_unstage_and_next(
17824        &mut self,
17825        stage: bool,
17826        window: &mut Window,
17827        cx: &mut Context<Self>,
17828    ) {
17829        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17830
17831        if ranges.iter().any(|range| range.start != range.end) {
17832            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17833            return;
17834        }
17835
17836        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17837        let snapshot = self.snapshot(window, cx);
17838        let position = self.selections.newest::<Point>(cx).head();
17839        let mut row = snapshot
17840            .buffer_snapshot
17841            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17842            .find(|hunk| hunk.row_range.start.0 > position.row)
17843            .map(|hunk| hunk.row_range.start);
17844
17845        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17846        // Outside of the project diff editor, wrap around to the beginning.
17847        if !all_diff_hunks_expanded {
17848            row = row.or_else(|| {
17849                snapshot
17850                    .buffer_snapshot
17851                    .diff_hunks_in_range(Point::zero()..position)
17852                    .find(|hunk| hunk.row_range.end.0 < position.row)
17853                    .map(|hunk| hunk.row_range.start)
17854            });
17855        }
17856
17857        if let Some(row) = row {
17858            let destination = Point::new(row.0, 0);
17859            let autoscroll = Autoscroll::center();
17860
17861            self.unfold_ranges(&[destination..destination], false, false, cx);
17862            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17863                s.select_ranges([destination..destination]);
17864            });
17865        }
17866    }
17867
17868    fn do_stage_or_unstage(
17869        &self,
17870        stage: bool,
17871        buffer_id: BufferId,
17872        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17873        cx: &mut App,
17874    ) -> Option<()> {
17875        let project = self.project.as_ref()?;
17876        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17877        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17878        let buffer_snapshot = buffer.read(cx).snapshot();
17879        let file_exists = buffer_snapshot
17880            .file()
17881            .is_some_and(|file| file.disk_state().exists());
17882        diff.update(cx, |diff, cx| {
17883            diff.stage_or_unstage_hunks(
17884                stage,
17885                &hunks
17886                    .map(|hunk| buffer_diff::DiffHunk {
17887                        buffer_range: hunk.buffer_range,
17888                        diff_base_byte_range: hunk.diff_base_byte_range,
17889                        secondary_status: hunk.secondary_status,
17890                        range: Point::zero()..Point::zero(), // unused
17891                    })
17892                    .collect::<Vec<_>>(),
17893                &buffer_snapshot,
17894                file_exists,
17895                cx,
17896            )
17897        });
17898        None
17899    }
17900
17901    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17902        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17903        self.buffer
17904            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17905    }
17906
17907    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17908        self.buffer.update(cx, |buffer, cx| {
17909            let ranges = vec![Anchor::min()..Anchor::max()];
17910            if !buffer.all_diff_hunks_expanded()
17911                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17912            {
17913                buffer.collapse_diff_hunks(ranges, cx);
17914                true
17915            } else {
17916                false
17917            }
17918        })
17919    }
17920
17921    fn toggle_diff_hunks_in_ranges(
17922        &mut self,
17923        ranges: Vec<Range<Anchor>>,
17924        cx: &mut Context<Editor>,
17925    ) {
17926        self.buffer.update(cx, |buffer, cx| {
17927            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17928            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17929        })
17930    }
17931
17932    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17933        self.buffer.update(cx, |buffer, cx| {
17934            let snapshot = buffer.snapshot(cx);
17935            let excerpt_id = range.end.excerpt_id;
17936            let point_range = range.to_point(&snapshot);
17937            let expand = !buffer.single_hunk_is_expanded(range, cx);
17938            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17939        })
17940    }
17941
17942    pub(crate) fn apply_all_diff_hunks(
17943        &mut self,
17944        _: &ApplyAllDiffHunks,
17945        window: &mut Window,
17946        cx: &mut Context<Self>,
17947    ) {
17948        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17949
17950        let buffers = self.buffer.read(cx).all_buffers();
17951        for branch_buffer in buffers {
17952            branch_buffer.update(cx, |branch_buffer, cx| {
17953                branch_buffer.merge_into_base(Vec::new(), cx);
17954            });
17955        }
17956
17957        if let Some(project) = self.project.clone() {
17958            self.save(
17959                SaveOptions {
17960                    format: true,
17961                    autosave: false,
17962                },
17963                project,
17964                window,
17965                cx,
17966            )
17967            .detach_and_log_err(cx);
17968        }
17969    }
17970
17971    pub(crate) fn apply_selected_diff_hunks(
17972        &mut self,
17973        _: &ApplyDiffHunk,
17974        window: &mut Window,
17975        cx: &mut Context<Self>,
17976    ) {
17977        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17978        let snapshot = self.snapshot(window, cx);
17979        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17980        let mut ranges_by_buffer = HashMap::default();
17981        self.transact(window, cx, |editor, _window, cx| {
17982            for hunk in hunks {
17983                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17984                    ranges_by_buffer
17985                        .entry(buffer.clone())
17986                        .or_insert_with(Vec::new)
17987                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17988                }
17989            }
17990
17991            for (buffer, ranges) in ranges_by_buffer {
17992                buffer.update(cx, |buffer, cx| {
17993                    buffer.merge_into_base(ranges, cx);
17994                });
17995            }
17996        });
17997
17998        if let Some(project) = self.project.clone() {
17999            self.save(
18000                SaveOptions {
18001                    format: true,
18002                    autosave: false,
18003                },
18004                project,
18005                window,
18006                cx,
18007            )
18008            .detach_and_log_err(cx);
18009        }
18010    }
18011
18012    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18013        if hovered != self.gutter_hovered {
18014            self.gutter_hovered = hovered;
18015            cx.notify();
18016        }
18017    }
18018
18019    pub fn insert_blocks(
18020        &mut self,
18021        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18022        autoscroll: Option<Autoscroll>,
18023        cx: &mut Context<Self>,
18024    ) -> Vec<CustomBlockId> {
18025        let blocks = self
18026            .display_map
18027            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18028        if let Some(autoscroll) = autoscroll {
18029            self.request_autoscroll(autoscroll, cx);
18030        }
18031        cx.notify();
18032        blocks
18033    }
18034
18035    pub fn resize_blocks(
18036        &mut self,
18037        heights: HashMap<CustomBlockId, u32>,
18038        autoscroll: Option<Autoscroll>,
18039        cx: &mut Context<Self>,
18040    ) {
18041        self.display_map
18042            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18043        if let Some(autoscroll) = autoscroll {
18044            self.request_autoscroll(autoscroll, cx);
18045        }
18046        cx.notify();
18047    }
18048
18049    pub fn replace_blocks(
18050        &mut self,
18051        renderers: HashMap<CustomBlockId, RenderBlock>,
18052        autoscroll: Option<Autoscroll>,
18053        cx: &mut Context<Self>,
18054    ) {
18055        self.display_map
18056            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18057        if let Some(autoscroll) = autoscroll {
18058            self.request_autoscroll(autoscroll, cx);
18059        }
18060        cx.notify();
18061    }
18062
18063    pub fn remove_blocks(
18064        &mut self,
18065        block_ids: HashSet<CustomBlockId>,
18066        autoscroll: Option<Autoscroll>,
18067        cx: &mut Context<Self>,
18068    ) {
18069        self.display_map.update(cx, |display_map, cx| {
18070            display_map.remove_blocks(block_ids, cx)
18071        });
18072        if let Some(autoscroll) = autoscroll {
18073            self.request_autoscroll(autoscroll, cx);
18074        }
18075        cx.notify();
18076    }
18077
18078    pub fn row_for_block(
18079        &self,
18080        block_id: CustomBlockId,
18081        cx: &mut Context<Self>,
18082    ) -> Option<DisplayRow> {
18083        self.display_map
18084            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18085    }
18086
18087    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18088        self.focused_block = Some(focused_block);
18089    }
18090
18091    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18092        self.focused_block.take()
18093    }
18094
18095    pub fn insert_creases(
18096        &mut self,
18097        creases: impl IntoIterator<Item = Crease<Anchor>>,
18098        cx: &mut Context<Self>,
18099    ) -> Vec<CreaseId> {
18100        self.display_map
18101            .update(cx, |map, cx| map.insert_creases(creases, cx))
18102    }
18103
18104    pub fn remove_creases(
18105        &mut self,
18106        ids: impl IntoIterator<Item = CreaseId>,
18107        cx: &mut Context<Self>,
18108    ) -> Vec<(CreaseId, Range<Anchor>)> {
18109        self.display_map
18110            .update(cx, |map, cx| map.remove_creases(ids, cx))
18111    }
18112
18113    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18114        self.display_map
18115            .update(cx, |map, cx| map.snapshot(cx))
18116            .longest_row()
18117    }
18118
18119    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18120        self.display_map
18121            .update(cx, |map, cx| map.snapshot(cx))
18122            .max_point()
18123    }
18124
18125    pub fn text(&self, cx: &App) -> String {
18126        self.buffer.read(cx).read(cx).text()
18127    }
18128
18129    pub fn is_empty(&self, cx: &App) -> bool {
18130        self.buffer.read(cx).read(cx).is_empty()
18131    }
18132
18133    pub fn text_option(&self, cx: &App) -> Option<String> {
18134        let text = self.text(cx);
18135        let text = text.trim();
18136
18137        if text.is_empty() {
18138            return None;
18139        }
18140
18141        Some(text.to_string())
18142    }
18143
18144    pub fn set_text(
18145        &mut self,
18146        text: impl Into<Arc<str>>,
18147        window: &mut Window,
18148        cx: &mut Context<Self>,
18149    ) {
18150        self.transact(window, cx, |this, _, cx| {
18151            this.buffer
18152                .read(cx)
18153                .as_singleton()
18154                .expect("you can only call set_text on editors for singleton buffers")
18155                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18156        });
18157    }
18158
18159    pub fn display_text(&self, cx: &mut App) -> String {
18160        self.display_map
18161            .update(cx, |map, cx| map.snapshot(cx))
18162            .text()
18163    }
18164
18165    fn create_minimap(
18166        &self,
18167        minimap_settings: MinimapSettings,
18168        window: &mut Window,
18169        cx: &mut Context<Self>,
18170    ) -> Option<Entity<Self>> {
18171        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18172            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18173    }
18174
18175    fn initialize_new_minimap(
18176        &self,
18177        minimap_settings: MinimapSettings,
18178        window: &mut Window,
18179        cx: &mut Context<Self>,
18180    ) -> Entity<Self> {
18181        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18182
18183        let mut minimap = Editor::new_internal(
18184            EditorMode::Minimap {
18185                parent: cx.weak_entity(),
18186            },
18187            self.buffer.clone(),
18188            None,
18189            Some(self.display_map.clone()),
18190            window,
18191            cx,
18192        );
18193        minimap.scroll_manager.clone_state(&self.scroll_manager);
18194        minimap.set_text_style_refinement(TextStyleRefinement {
18195            font_size: Some(MINIMAP_FONT_SIZE),
18196            font_weight: Some(MINIMAP_FONT_WEIGHT),
18197            ..Default::default()
18198        });
18199        minimap.update_minimap_configuration(minimap_settings, cx);
18200        cx.new(|_| minimap)
18201    }
18202
18203    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18204        let current_line_highlight = minimap_settings
18205            .current_line_highlight
18206            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18207        self.set_current_line_highlight(Some(current_line_highlight));
18208    }
18209
18210    pub fn minimap(&self) -> Option<&Entity<Self>> {
18211        self.minimap
18212            .as_ref()
18213            .filter(|_| self.minimap_visibility.visible())
18214    }
18215
18216    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18217        let mut wrap_guides = smallvec![];
18218
18219        if self.show_wrap_guides == Some(false) {
18220            return wrap_guides;
18221        }
18222
18223        let settings = self.buffer.read(cx).language_settings(cx);
18224        if settings.show_wrap_guides {
18225            match self.soft_wrap_mode(cx) {
18226                SoftWrap::Column(soft_wrap) => {
18227                    wrap_guides.push((soft_wrap as usize, true));
18228                }
18229                SoftWrap::Bounded(soft_wrap) => {
18230                    wrap_guides.push((soft_wrap as usize, true));
18231                }
18232                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18233            }
18234            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18235        }
18236
18237        wrap_guides
18238    }
18239
18240    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18241        let settings = self.buffer.read(cx).language_settings(cx);
18242        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18243        match mode {
18244            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18245                SoftWrap::None
18246            }
18247            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18248            language_settings::SoftWrap::PreferredLineLength => {
18249                SoftWrap::Column(settings.preferred_line_length)
18250            }
18251            language_settings::SoftWrap::Bounded => {
18252                SoftWrap::Bounded(settings.preferred_line_length)
18253            }
18254        }
18255    }
18256
18257    pub fn set_soft_wrap_mode(
18258        &mut self,
18259        mode: language_settings::SoftWrap,
18260
18261        cx: &mut Context<Self>,
18262    ) {
18263        self.soft_wrap_mode_override = Some(mode);
18264        cx.notify();
18265    }
18266
18267    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18268        self.hard_wrap = hard_wrap;
18269        cx.notify();
18270    }
18271
18272    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18273        self.text_style_refinement = Some(style);
18274    }
18275
18276    /// called by the Element so we know what style we were most recently rendered with.
18277    pub(crate) fn set_style(
18278        &mut self,
18279        style: EditorStyle,
18280        window: &mut Window,
18281        cx: &mut Context<Self>,
18282    ) {
18283        // We intentionally do not inform the display map about the minimap style
18284        // so that wrapping is not recalculated and stays consistent for the editor
18285        // and its linked minimap.
18286        if !self.mode.is_minimap() {
18287            let rem_size = window.rem_size();
18288            self.display_map.update(cx, |map, cx| {
18289                map.set_font(
18290                    style.text.font(),
18291                    style.text.font_size.to_pixels(rem_size),
18292                    cx,
18293                )
18294            });
18295        }
18296        self.style = Some(style);
18297    }
18298
18299    pub fn style(&self) -> Option<&EditorStyle> {
18300        self.style.as_ref()
18301    }
18302
18303    // Called by the element. This method is not designed to be called outside of the editor
18304    // element's layout code because it does not notify when rewrapping is computed synchronously.
18305    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18306        self.display_map
18307            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18308    }
18309
18310    pub fn set_soft_wrap(&mut self) {
18311        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18312    }
18313
18314    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18315        if self.soft_wrap_mode_override.is_some() {
18316            self.soft_wrap_mode_override.take();
18317        } else {
18318            let soft_wrap = match self.soft_wrap_mode(cx) {
18319                SoftWrap::GitDiff => return,
18320                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18321                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18322                    language_settings::SoftWrap::None
18323                }
18324            };
18325            self.soft_wrap_mode_override = Some(soft_wrap);
18326        }
18327        cx.notify();
18328    }
18329
18330    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18331        let Some(workspace) = self.workspace() else {
18332            return;
18333        };
18334        let fs = workspace.read(cx).app_state().fs.clone();
18335        let current_show = TabBarSettings::get_global(cx).show;
18336        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18337            setting.show = Some(!current_show);
18338        });
18339    }
18340
18341    pub fn toggle_indent_guides(
18342        &mut self,
18343        _: &ToggleIndentGuides,
18344        _: &mut Window,
18345        cx: &mut Context<Self>,
18346    ) {
18347        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18348            self.buffer
18349                .read(cx)
18350                .language_settings(cx)
18351                .indent_guides
18352                .enabled
18353        });
18354        self.show_indent_guides = Some(!currently_enabled);
18355        cx.notify();
18356    }
18357
18358    fn should_show_indent_guides(&self) -> Option<bool> {
18359        self.show_indent_guides
18360    }
18361
18362    pub fn toggle_line_numbers(
18363        &mut self,
18364        _: &ToggleLineNumbers,
18365        _: &mut Window,
18366        cx: &mut Context<Self>,
18367    ) {
18368        let mut editor_settings = EditorSettings::get_global(cx).clone();
18369        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18370        EditorSettings::override_global(editor_settings, cx);
18371    }
18372
18373    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18374        if let Some(show_line_numbers) = self.show_line_numbers {
18375            return show_line_numbers;
18376        }
18377        EditorSettings::get_global(cx).gutter.line_numbers
18378    }
18379
18380    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18381        self.use_relative_line_numbers
18382            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18383    }
18384
18385    pub fn toggle_relative_line_numbers(
18386        &mut self,
18387        _: &ToggleRelativeLineNumbers,
18388        _: &mut Window,
18389        cx: &mut Context<Self>,
18390    ) {
18391        let is_relative = self.should_use_relative_line_numbers(cx);
18392        self.set_relative_line_number(Some(!is_relative), cx)
18393    }
18394
18395    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18396        self.use_relative_line_numbers = is_relative;
18397        cx.notify();
18398    }
18399
18400    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18401        self.show_gutter = show_gutter;
18402        cx.notify();
18403    }
18404
18405    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18406        self.show_scrollbars = ScrollbarAxes {
18407            horizontal: show,
18408            vertical: show,
18409        };
18410        cx.notify();
18411    }
18412
18413    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18414        self.show_scrollbars.vertical = show;
18415        cx.notify();
18416    }
18417
18418    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18419        self.show_scrollbars.horizontal = show;
18420        cx.notify();
18421    }
18422
18423    pub fn set_minimap_visibility(
18424        &mut self,
18425        minimap_visibility: MinimapVisibility,
18426        window: &mut Window,
18427        cx: &mut Context<Self>,
18428    ) {
18429        if self.minimap_visibility != minimap_visibility {
18430            if minimap_visibility.visible() && self.minimap.is_none() {
18431                let minimap_settings = EditorSettings::get_global(cx).minimap;
18432                self.minimap =
18433                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18434            }
18435            self.minimap_visibility = minimap_visibility;
18436            cx.notify();
18437        }
18438    }
18439
18440    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18441        self.set_show_scrollbars(false, cx);
18442        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18443    }
18444
18445    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18446        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18447    }
18448
18449    /// Normally the text in full mode and auto height editors is padded on the
18450    /// left side by roughly half a character width for improved hit testing.
18451    ///
18452    /// Use this method to disable this for cases where this is not wanted (e.g.
18453    /// if you want to align the editor text with some other text above or below)
18454    /// or if you want to add this padding to single-line editors.
18455    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18456        self.offset_content = offset_content;
18457        cx.notify();
18458    }
18459
18460    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18461        self.show_line_numbers = Some(show_line_numbers);
18462        cx.notify();
18463    }
18464
18465    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18466        self.disable_expand_excerpt_buttons = true;
18467        cx.notify();
18468    }
18469
18470    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18471        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18472        cx.notify();
18473    }
18474
18475    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18476        self.show_code_actions = Some(show_code_actions);
18477        cx.notify();
18478    }
18479
18480    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18481        self.show_runnables = Some(show_runnables);
18482        cx.notify();
18483    }
18484
18485    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18486        self.show_breakpoints = Some(show_breakpoints);
18487        cx.notify();
18488    }
18489
18490    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18491        if self.display_map.read(cx).masked != masked {
18492            self.display_map.update(cx, |map, _| map.masked = masked);
18493        }
18494        cx.notify()
18495    }
18496
18497    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18498        self.show_wrap_guides = Some(show_wrap_guides);
18499        cx.notify();
18500    }
18501
18502    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18503        self.show_indent_guides = Some(show_indent_guides);
18504        cx.notify();
18505    }
18506
18507    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18508        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18509            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
18510                if let Some(dir) = file.abs_path(cx).parent() {
18511                    return Some(dir.to_owned());
18512                }
18513            }
18514
18515            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18516                return Some(project_path.path.to_path_buf());
18517            }
18518        }
18519
18520        None
18521    }
18522
18523    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18524        self.active_excerpt(cx)?
18525            .1
18526            .read(cx)
18527            .file()
18528            .and_then(|f| f.as_local())
18529    }
18530
18531    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18532        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18533            let buffer = buffer.read(cx);
18534            if let Some(project_path) = buffer.project_path(cx) {
18535                let project = self.project.as_ref()?.read(cx);
18536                project.absolute_path(&project_path, cx)
18537            } else {
18538                buffer
18539                    .file()
18540                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18541            }
18542        })
18543    }
18544
18545    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18546        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18547            let project_path = buffer.read(cx).project_path(cx)?;
18548            let project = self.project.as_ref()?.read(cx);
18549            let entry = project.entry_for_path(&project_path, cx)?;
18550            let path = entry.path.to_path_buf();
18551            Some(path)
18552        })
18553    }
18554
18555    pub fn reveal_in_finder(
18556        &mut self,
18557        _: &RevealInFileManager,
18558        _window: &mut Window,
18559        cx: &mut Context<Self>,
18560    ) {
18561        if let Some(target) = self.target_file(cx) {
18562            cx.reveal_path(&target.abs_path(cx));
18563        }
18564    }
18565
18566    pub fn copy_path(
18567        &mut self,
18568        _: &zed_actions::workspace::CopyPath,
18569        _window: &mut Window,
18570        cx: &mut Context<Self>,
18571    ) {
18572        if let Some(path) = self.target_file_abs_path(cx) {
18573            if let Some(path) = path.to_str() {
18574                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18575            }
18576        }
18577    }
18578
18579    pub fn copy_relative_path(
18580        &mut self,
18581        _: &zed_actions::workspace::CopyRelativePath,
18582        _window: &mut Window,
18583        cx: &mut Context<Self>,
18584    ) {
18585        if let Some(path) = self.target_file_path(cx) {
18586            if let Some(path) = path.to_str() {
18587                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18588            }
18589        }
18590    }
18591
18592    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18593        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18594            buffer.read(cx).project_path(cx)
18595        } else {
18596            None
18597        }
18598    }
18599
18600    // Returns true if the editor handled a go-to-line request
18601    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18602        maybe!({
18603            let breakpoint_store = self.breakpoint_store.as_ref()?;
18604
18605            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18606            else {
18607                self.clear_row_highlights::<ActiveDebugLine>();
18608                return None;
18609            };
18610
18611            let position = active_stack_frame.position;
18612            let buffer_id = position.buffer_id?;
18613            let snapshot = self
18614                .project
18615                .as_ref()?
18616                .read(cx)
18617                .buffer_for_id(buffer_id, cx)?
18618                .read(cx)
18619                .snapshot();
18620
18621            let mut handled = false;
18622            for (id, ExcerptRange { context, .. }) in
18623                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18624            {
18625                if context.start.cmp(&position, &snapshot).is_ge()
18626                    || context.end.cmp(&position, &snapshot).is_lt()
18627                {
18628                    continue;
18629                }
18630                let snapshot = self.buffer.read(cx).snapshot(cx);
18631                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18632
18633                handled = true;
18634                self.clear_row_highlights::<ActiveDebugLine>();
18635
18636                self.go_to_line::<ActiveDebugLine>(
18637                    multibuffer_anchor,
18638                    Some(cx.theme().colors().editor_debugger_active_line_background),
18639                    window,
18640                    cx,
18641                );
18642
18643                cx.notify();
18644            }
18645
18646            handled.then_some(())
18647        })
18648        .is_some()
18649    }
18650
18651    pub fn copy_file_name_without_extension(
18652        &mut self,
18653        _: &CopyFileNameWithoutExtension,
18654        _: &mut Window,
18655        cx: &mut Context<Self>,
18656    ) {
18657        if let Some(file) = self.target_file(cx) {
18658            if let Some(file_stem) = file.path().file_stem() {
18659                if let Some(name) = file_stem.to_str() {
18660                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18661                }
18662            }
18663        }
18664    }
18665
18666    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18667        if let Some(file) = self.target_file(cx) {
18668            if let Some(file_name) = file.path().file_name() {
18669                if let Some(name) = file_name.to_str() {
18670                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18671                }
18672            }
18673        }
18674    }
18675
18676    pub fn toggle_git_blame(
18677        &mut self,
18678        _: &::git::Blame,
18679        window: &mut Window,
18680        cx: &mut Context<Self>,
18681    ) {
18682        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18683
18684        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18685            self.start_git_blame(true, window, cx);
18686        }
18687
18688        cx.notify();
18689    }
18690
18691    pub fn toggle_git_blame_inline(
18692        &mut self,
18693        _: &ToggleGitBlameInline,
18694        window: &mut Window,
18695        cx: &mut Context<Self>,
18696    ) {
18697        self.toggle_git_blame_inline_internal(true, window, cx);
18698        cx.notify();
18699    }
18700
18701    pub fn open_git_blame_commit(
18702        &mut self,
18703        _: &OpenGitBlameCommit,
18704        window: &mut Window,
18705        cx: &mut Context<Self>,
18706    ) {
18707        self.open_git_blame_commit_internal(window, cx);
18708    }
18709
18710    fn open_git_blame_commit_internal(
18711        &mut self,
18712        window: &mut Window,
18713        cx: &mut Context<Self>,
18714    ) -> Option<()> {
18715        let blame = self.blame.as_ref()?;
18716        let snapshot = self.snapshot(window, cx);
18717        let cursor = self.selections.newest::<Point>(cx).head();
18718        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18719        let blame_entry = blame
18720            .update(cx, |blame, cx| {
18721                blame
18722                    .blame_for_rows(
18723                        &[RowInfo {
18724                            buffer_id: Some(buffer.remote_id()),
18725                            buffer_row: Some(point.row),
18726                            ..Default::default()
18727                        }],
18728                        cx,
18729                    )
18730                    .next()
18731            })
18732            .flatten()?;
18733        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18734        let repo = blame.read(cx).repository(cx)?;
18735        let workspace = self.workspace()?.downgrade();
18736        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18737        None
18738    }
18739
18740    pub fn git_blame_inline_enabled(&self) -> bool {
18741        self.git_blame_inline_enabled
18742    }
18743
18744    pub fn toggle_selection_menu(
18745        &mut self,
18746        _: &ToggleSelectionMenu,
18747        _: &mut Window,
18748        cx: &mut Context<Self>,
18749    ) {
18750        self.show_selection_menu = self
18751            .show_selection_menu
18752            .map(|show_selections_menu| !show_selections_menu)
18753            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18754
18755        cx.notify();
18756    }
18757
18758    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18759        self.show_selection_menu
18760            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18761    }
18762
18763    fn start_git_blame(
18764        &mut self,
18765        user_triggered: bool,
18766        window: &mut Window,
18767        cx: &mut Context<Self>,
18768    ) {
18769        if let Some(project) = self.project.as_ref() {
18770            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18771                return;
18772            };
18773
18774            if buffer.read(cx).file().is_none() {
18775                return;
18776            }
18777
18778            let focused = self.focus_handle(cx).contains_focused(window, cx);
18779
18780            let project = project.clone();
18781            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18782            self.blame_subscription =
18783                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18784            self.blame = Some(blame);
18785        }
18786    }
18787
18788    fn toggle_git_blame_inline_internal(
18789        &mut self,
18790        user_triggered: bool,
18791        window: &mut Window,
18792        cx: &mut Context<Self>,
18793    ) {
18794        if self.git_blame_inline_enabled {
18795            self.git_blame_inline_enabled = false;
18796            self.show_git_blame_inline = false;
18797            self.show_git_blame_inline_delay_task.take();
18798        } else {
18799            self.git_blame_inline_enabled = true;
18800            self.start_git_blame_inline(user_triggered, window, cx);
18801        }
18802
18803        cx.notify();
18804    }
18805
18806    fn start_git_blame_inline(
18807        &mut self,
18808        user_triggered: bool,
18809        window: &mut Window,
18810        cx: &mut Context<Self>,
18811    ) {
18812        self.start_git_blame(user_triggered, window, cx);
18813
18814        if ProjectSettings::get_global(cx)
18815            .git
18816            .inline_blame_delay()
18817            .is_some()
18818        {
18819            self.start_inline_blame_timer(window, cx);
18820        } else {
18821            self.show_git_blame_inline = true
18822        }
18823    }
18824
18825    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18826        self.blame.as_ref()
18827    }
18828
18829    pub fn show_git_blame_gutter(&self) -> bool {
18830        self.show_git_blame_gutter
18831    }
18832
18833    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18834        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18835    }
18836
18837    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18838        self.show_git_blame_inline
18839            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18840            && !self.newest_selection_head_on_empty_line(cx)
18841            && self.has_blame_entries(cx)
18842    }
18843
18844    fn has_blame_entries(&self, cx: &App) -> bool {
18845        self.blame()
18846            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18847    }
18848
18849    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18850        let cursor_anchor = self.selections.newest_anchor().head();
18851
18852        let snapshot = self.buffer.read(cx).snapshot(cx);
18853        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18854
18855        snapshot.line_len(buffer_row) == 0
18856    }
18857
18858    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18859        let buffer_and_selection = maybe!({
18860            let selection = self.selections.newest::<Point>(cx);
18861            let selection_range = selection.range();
18862
18863            let multi_buffer = self.buffer().read(cx);
18864            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18865            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18866
18867            let (buffer, range, _) = if selection.reversed {
18868                buffer_ranges.first()
18869            } else {
18870                buffer_ranges.last()
18871            }?;
18872
18873            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18874                ..text::ToPoint::to_point(&range.end, &buffer).row;
18875            Some((
18876                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18877                selection,
18878            ))
18879        });
18880
18881        let Some((buffer, selection)) = buffer_and_selection else {
18882            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18883        };
18884
18885        let Some(project) = self.project.as_ref() else {
18886            return Task::ready(Err(anyhow!("editor does not have project")));
18887        };
18888
18889        project.update(cx, |project, cx| {
18890            project.get_permalink_to_line(&buffer, selection, cx)
18891        })
18892    }
18893
18894    pub fn copy_permalink_to_line(
18895        &mut self,
18896        _: &CopyPermalinkToLine,
18897        window: &mut Window,
18898        cx: &mut Context<Self>,
18899    ) {
18900        let permalink_task = self.get_permalink_to_line(cx);
18901        let workspace = self.workspace();
18902
18903        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18904            Ok(permalink) => {
18905                cx.update(|_, cx| {
18906                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18907                })
18908                .ok();
18909            }
18910            Err(err) => {
18911                let message = format!("Failed to copy permalink: {err}");
18912
18913                anyhow::Result::<()>::Err(err).log_err();
18914
18915                if let Some(workspace) = workspace {
18916                    workspace
18917                        .update_in(cx, |workspace, _, cx| {
18918                            struct CopyPermalinkToLine;
18919
18920                            workspace.show_toast(
18921                                Toast::new(
18922                                    NotificationId::unique::<CopyPermalinkToLine>(),
18923                                    message,
18924                                ),
18925                                cx,
18926                            )
18927                        })
18928                        .ok();
18929                }
18930            }
18931        })
18932        .detach();
18933    }
18934
18935    pub fn copy_file_location(
18936        &mut self,
18937        _: &CopyFileLocation,
18938        _: &mut Window,
18939        cx: &mut Context<Self>,
18940    ) {
18941        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18942        if let Some(file) = self.target_file(cx) {
18943            if let Some(path) = file.path().to_str() {
18944                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18945            }
18946        }
18947    }
18948
18949    pub fn open_permalink_to_line(
18950        &mut self,
18951        _: &OpenPermalinkToLine,
18952        window: &mut Window,
18953        cx: &mut Context<Self>,
18954    ) {
18955        let permalink_task = self.get_permalink_to_line(cx);
18956        let workspace = self.workspace();
18957
18958        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18959            Ok(permalink) => {
18960                cx.update(|_, cx| {
18961                    cx.open_url(permalink.as_ref());
18962                })
18963                .ok();
18964            }
18965            Err(err) => {
18966                let message = format!("Failed to open permalink: {err}");
18967
18968                anyhow::Result::<()>::Err(err).log_err();
18969
18970                if let Some(workspace) = workspace {
18971                    workspace
18972                        .update(cx, |workspace, cx| {
18973                            struct OpenPermalinkToLine;
18974
18975                            workspace.show_toast(
18976                                Toast::new(
18977                                    NotificationId::unique::<OpenPermalinkToLine>(),
18978                                    message,
18979                                ),
18980                                cx,
18981                            )
18982                        })
18983                        .ok();
18984                }
18985            }
18986        })
18987        .detach();
18988    }
18989
18990    pub fn insert_uuid_v4(
18991        &mut self,
18992        _: &InsertUuidV4,
18993        window: &mut Window,
18994        cx: &mut Context<Self>,
18995    ) {
18996        self.insert_uuid(UuidVersion::V4, window, cx);
18997    }
18998
18999    pub fn insert_uuid_v7(
19000        &mut self,
19001        _: &InsertUuidV7,
19002        window: &mut Window,
19003        cx: &mut Context<Self>,
19004    ) {
19005        self.insert_uuid(UuidVersion::V7, window, cx);
19006    }
19007
19008    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19009        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19010        self.transact(window, cx, |this, window, cx| {
19011            let edits = this
19012                .selections
19013                .all::<Point>(cx)
19014                .into_iter()
19015                .map(|selection| {
19016                    let uuid = match version {
19017                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19018                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19019                    };
19020
19021                    (selection.range(), uuid.to_string())
19022                });
19023            this.edit(edits, cx);
19024            this.refresh_inline_completion(true, false, window, cx);
19025        });
19026    }
19027
19028    pub fn open_selections_in_multibuffer(
19029        &mut self,
19030        _: &OpenSelectionsInMultibuffer,
19031        window: &mut Window,
19032        cx: &mut Context<Self>,
19033    ) {
19034        let multibuffer = self.buffer.read(cx);
19035
19036        let Some(buffer) = multibuffer.as_singleton() else {
19037            return;
19038        };
19039
19040        let Some(workspace) = self.workspace() else {
19041            return;
19042        };
19043
19044        let title = multibuffer.title(cx).to_string();
19045
19046        let locations = self
19047            .selections
19048            .all_anchors(cx)
19049            .into_iter()
19050            .map(|selection| Location {
19051                buffer: buffer.clone(),
19052                range: selection.start.text_anchor..selection.end.text_anchor,
19053            })
19054            .collect::<Vec<_>>();
19055
19056        cx.spawn_in(window, async move |_, cx| {
19057            workspace.update_in(cx, |workspace, window, cx| {
19058                Self::open_locations_in_multibuffer(
19059                    workspace,
19060                    locations,
19061                    format!("Selections for '{title}'"),
19062                    false,
19063                    MultibufferSelectionMode::All,
19064                    window,
19065                    cx,
19066                );
19067            })
19068        })
19069        .detach();
19070    }
19071
19072    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19073    /// last highlight added will be used.
19074    ///
19075    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19076    pub fn highlight_rows<T: 'static>(
19077        &mut self,
19078        range: Range<Anchor>,
19079        color: Hsla,
19080        options: RowHighlightOptions,
19081        cx: &mut Context<Self>,
19082    ) {
19083        let snapshot = self.buffer().read(cx).snapshot(cx);
19084        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19085        let ix = row_highlights.binary_search_by(|highlight| {
19086            Ordering::Equal
19087                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19088                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19089        });
19090
19091        if let Err(mut ix) = ix {
19092            let index = post_inc(&mut self.highlight_order);
19093
19094            // If this range intersects with the preceding highlight, then merge it with
19095            // the preceding highlight. Otherwise insert a new highlight.
19096            let mut merged = false;
19097            if ix > 0 {
19098                let prev_highlight = &mut row_highlights[ix - 1];
19099                if prev_highlight
19100                    .range
19101                    .end
19102                    .cmp(&range.start, &snapshot)
19103                    .is_ge()
19104                {
19105                    ix -= 1;
19106                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19107                        prev_highlight.range.end = range.end;
19108                    }
19109                    merged = true;
19110                    prev_highlight.index = index;
19111                    prev_highlight.color = color;
19112                    prev_highlight.options = options;
19113                }
19114            }
19115
19116            if !merged {
19117                row_highlights.insert(
19118                    ix,
19119                    RowHighlight {
19120                        range: range.clone(),
19121                        index,
19122                        color,
19123                        options,
19124                        type_id: TypeId::of::<T>(),
19125                    },
19126                );
19127            }
19128
19129            // If any of the following highlights intersect with this one, merge them.
19130            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19131                let highlight = &row_highlights[ix];
19132                if next_highlight
19133                    .range
19134                    .start
19135                    .cmp(&highlight.range.end, &snapshot)
19136                    .is_le()
19137                {
19138                    if next_highlight
19139                        .range
19140                        .end
19141                        .cmp(&highlight.range.end, &snapshot)
19142                        .is_gt()
19143                    {
19144                        row_highlights[ix].range.end = next_highlight.range.end;
19145                    }
19146                    row_highlights.remove(ix + 1);
19147                } else {
19148                    break;
19149                }
19150            }
19151        }
19152    }
19153
19154    /// Remove any highlighted row ranges of the given type that intersect the
19155    /// given ranges.
19156    pub fn remove_highlighted_rows<T: 'static>(
19157        &mut self,
19158        ranges_to_remove: Vec<Range<Anchor>>,
19159        cx: &mut Context<Self>,
19160    ) {
19161        let snapshot = self.buffer().read(cx).snapshot(cx);
19162        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19163        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19164        row_highlights.retain(|highlight| {
19165            while let Some(range_to_remove) = ranges_to_remove.peek() {
19166                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19167                    Ordering::Less | Ordering::Equal => {
19168                        ranges_to_remove.next();
19169                    }
19170                    Ordering::Greater => {
19171                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19172                            Ordering::Less | Ordering::Equal => {
19173                                return false;
19174                            }
19175                            Ordering::Greater => break,
19176                        }
19177                    }
19178                }
19179            }
19180
19181            true
19182        })
19183    }
19184
19185    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19186    pub fn clear_row_highlights<T: 'static>(&mut self) {
19187        self.highlighted_rows.remove(&TypeId::of::<T>());
19188    }
19189
19190    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19191    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19192        self.highlighted_rows
19193            .get(&TypeId::of::<T>())
19194            .map_or(&[] as &[_], |vec| vec.as_slice())
19195            .iter()
19196            .map(|highlight| (highlight.range.clone(), highlight.color))
19197    }
19198
19199    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19200    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19201    /// Allows to ignore certain kinds of highlights.
19202    pub fn highlighted_display_rows(
19203        &self,
19204        window: &mut Window,
19205        cx: &mut App,
19206    ) -> BTreeMap<DisplayRow, LineHighlight> {
19207        let snapshot = self.snapshot(window, cx);
19208        let mut used_highlight_orders = HashMap::default();
19209        self.highlighted_rows
19210            .iter()
19211            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19212            .fold(
19213                BTreeMap::<DisplayRow, LineHighlight>::new(),
19214                |mut unique_rows, highlight| {
19215                    let start = highlight.range.start.to_display_point(&snapshot);
19216                    let end = highlight.range.end.to_display_point(&snapshot);
19217                    let start_row = start.row().0;
19218                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19219                        && end.column() == 0
19220                    {
19221                        end.row().0.saturating_sub(1)
19222                    } else {
19223                        end.row().0
19224                    };
19225                    for row in start_row..=end_row {
19226                        let used_index =
19227                            used_highlight_orders.entry(row).or_insert(highlight.index);
19228                        if highlight.index >= *used_index {
19229                            *used_index = highlight.index;
19230                            unique_rows.insert(
19231                                DisplayRow(row),
19232                                LineHighlight {
19233                                    include_gutter: highlight.options.include_gutter,
19234                                    border: None,
19235                                    background: highlight.color.into(),
19236                                    type_id: Some(highlight.type_id),
19237                                },
19238                            );
19239                        }
19240                    }
19241                    unique_rows
19242                },
19243            )
19244    }
19245
19246    pub fn highlighted_display_row_for_autoscroll(
19247        &self,
19248        snapshot: &DisplaySnapshot,
19249    ) -> Option<DisplayRow> {
19250        self.highlighted_rows
19251            .values()
19252            .flat_map(|highlighted_rows| highlighted_rows.iter())
19253            .filter_map(|highlight| {
19254                if highlight.options.autoscroll {
19255                    Some(highlight.range.start.to_display_point(snapshot).row())
19256                } else {
19257                    None
19258                }
19259            })
19260            .min()
19261    }
19262
19263    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19264        self.highlight_background::<SearchWithinRange>(
19265            ranges,
19266            |colors| colors.colors().editor_document_highlight_read_background,
19267            cx,
19268        )
19269    }
19270
19271    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19272        self.breadcrumb_header = Some(new_header);
19273    }
19274
19275    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19276        self.clear_background_highlights::<SearchWithinRange>(cx);
19277    }
19278
19279    pub fn highlight_background<T: 'static>(
19280        &mut self,
19281        ranges: &[Range<Anchor>],
19282        color_fetcher: fn(&Theme) -> Hsla,
19283        cx: &mut Context<Self>,
19284    ) {
19285        self.background_highlights.insert(
19286            HighlightKey::Type(TypeId::of::<T>()),
19287            (color_fetcher, Arc::from(ranges)),
19288        );
19289        self.scrollbar_marker_state.dirty = true;
19290        cx.notify();
19291    }
19292
19293    pub fn highlight_background_key<T: 'static>(
19294        &mut self,
19295        key: usize,
19296        ranges: &[Range<Anchor>],
19297        color_fetcher: fn(&Theme) -> Hsla,
19298        cx: &mut Context<Self>,
19299    ) {
19300        self.background_highlights.insert(
19301            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19302            (color_fetcher, Arc::from(ranges)),
19303        );
19304        self.scrollbar_marker_state.dirty = true;
19305        cx.notify();
19306    }
19307
19308    pub fn clear_background_highlights<T: 'static>(
19309        &mut self,
19310        cx: &mut Context<Self>,
19311    ) -> Option<BackgroundHighlight> {
19312        let text_highlights = self
19313            .background_highlights
19314            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19315        if !text_highlights.1.is_empty() {
19316            self.scrollbar_marker_state.dirty = true;
19317            cx.notify();
19318        }
19319        Some(text_highlights)
19320    }
19321
19322    pub fn highlight_gutter<T: 'static>(
19323        &mut self,
19324        ranges: impl Into<Vec<Range<Anchor>>>,
19325        color_fetcher: fn(&App) -> Hsla,
19326        cx: &mut Context<Self>,
19327    ) {
19328        self.gutter_highlights
19329            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19330        cx.notify();
19331    }
19332
19333    pub fn clear_gutter_highlights<T: 'static>(
19334        &mut self,
19335        cx: &mut Context<Self>,
19336    ) -> Option<GutterHighlight> {
19337        cx.notify();
19338        self.gutter_highlights.remove(&TypeId::of::<T>())
19339    }
19340
19341    pub fn insert_gutter_highlight<T: 'static>(
19342        &mut self,
19343        range: Range<Anchor>,
19344        color_fetcher: fn(&App) -> Hsla,
19345        cx: &mut Context<Self>,
19346    ) {
19347        let snapshot = self.buffer().read(cx).snapshot(cx);
19348        let mut highlights = self
19349            .gutter_highlights
19350            .remove(&TypeId::of::<T>())
19351            .map(|(_, highlights)| highlights)
19352            .unwrap_or_default();
19353        let ix = highlights.binary_search_by(|highlight| {
19354            Ordering::Equal
19355                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19356                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19357        });
19358        if let Err(ix) = ix {
19359            highlights.insert(ix, range);
19360        }
19361        self.gutter_highlights
19362            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19363    }
19364
19365    pub fn remove_gutter_highlights<T: 'static>(
19366        &mut self,
19367        ranges_to_remove: Vec<Range<Anchor>>,
19368        cx: &mut Context<Self>,
19369    ) {
19370        let snapshot = self.buffer().read(cx).snapshot(cx);
19371        let Some((color_fetcher, mut gutter_highlights)) =
19372            self.gutter_highlights.remove(&TypeId::of::<T>())
19373        else {
19374            return;
19375        };
19376        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19377        gutter_highlights.retain(|highlight| {
19378            while let Some(range_to_remove) = ranges_to_remove.peek() {
19379                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19380                    Ordering::Less | Ordering::Equal => {
19381                        ranges_to_remove.next();
19382                    }
19383                    Ordering::Greater => {
19384                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19385                            Ordering::Less | Ordering::Equal => {
19386                                return false;
19387                            }
19388                            Ordering::Greater => break,
19389                        }
19390                    }
19391                }
19392            }
19393
19394            true
19395        });
19396        self.gutter_highlights
19397            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19398    }
19399
19400    #[cfg(feature = "test-support")]
19401    pub fn all_text_highlights(
19402        &self,
19403        window: &mut Window,
19404        cx: &mut Context<Self>,
19405    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19406        let snapshot = self.snapshot(window, cx);
19407        self.display_map.update(cx, |display_map, _| {
19408            display_map
19409                .all_text_highlights()
19410                .map(|highlight| {
19411                    let (style, ranges) = highlight.as_ref();
19412                    (
19413                        *style,
19414                        ranges
19415                            .iter()
19416                            .map(|range| range.clone().to_display_points(&snapshot))
19417                            .collect(),
19418                    )
19419                })
19420                .collect()
19421        })
19422    }
19423
19424    #[cfg(feature = "test-support")]
19425    pub fn all_text_background_highlights(
19426        &self,
19427        window: &mut Window,
19428        cx: &mut Context<Self>,
19429    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19430        let snapshot = self.snapshot(window, cx);
19431        let buffer = &snapshot.buffer_snapshot;
19432        let start = buffer.anchor_before(0);
19433        let end = buffer.anchor_after(buffer.len());
19434        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19435    }
19436
19437    #[cfg(feature = "test-support")]
19438    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19439        let snapshot = self.buffer().read(cx).snapshot(cx);
19440
19441        let highlights = self
19442            .background_highlights
19443            .get(&HighlightKey::Type(TypeId::of::<
19444                items::BufferSearchHighlights,
19445            >()));
19446
19447        if let Some((_color, ranges)) = highlights {
19448            ranges
19449                .iter()
19450                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19451                .collect_vec()
19452        } else {
19453            vec![]
19454        }
19455    }
19456
19457    fn document_highlights_for_position<'a>(
19458        &'a self,
19459        position: Anchor,
19460        buffer: &'a MultiBufferSnapshot,
19461    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19462        let read_highlights = self
19463            .background_highlights
19464            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19465            .map(|h| &h.1);
19466        let write_highlights = self
19467            .background_highlights
19468            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19469            .map(|h| &h.1);
19470        let left_position = position.bias_left(buffer);
19471        let right_position = position.bias_right(buffer);
19472        read_highlights
19473            .into_iter()
19474            .chain(write_highlights)
19475            .flat_map(move |ranges| {
19476                let start_ix = match ranges.binary_search_by(|probe| {
19477                    let cmp = probe.end.cmp(&left_position, buffer);
19478                    if cmp.is_ge() {
19479                        Ordering::Greater
19480                    } else {
19481                        Ordering::Less
19482                    }
19483                }) {
19484                    Ok(i) | Err(i) => i,
19485                };
19486
19487                ranges[start_ix..]
19488                    .iter()
19489                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19490            })
19491    }
19492
19493    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19494        self.background_highlights
19495            .get(&HighlightKey::Type(TypeId::of::<T>()))
19496            .map_or(false, |(_, highlights)| !highlights.is_empty())
19497    }
19498
19499    pub fn background_highlights_in_range(
19500        &self,
19501        search_range: Range<Anchor>,
19502        display_snapshot: &DisplaySnapshot,
19503        theme: &Theme,
19504    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19505        let mut results = Vec::new();
19506        for (color_fetcher, ranges) in self.background_highlights.values() {
19507            let color = color_fetcher(theme);
19508            let start_ix = match ranges.binary_search_by(|probe| {
19509                let cmp = probe
19510                    .end
19511                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19512                if cmp.is_gt() {
19513                    Ordering::Greater
19514                } else {
19515                    Ordering::Less
19516                }
19517            }) {
19518                Ok(i) | Err(i) => i,
19519            };
19520            for range in &ranges[start_ix..] {
19521                if range
19522                    .start
19523                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19524                    .is_ge()
19525                {
19526                    break;
19527                }
19528
19529                let start = range.start.to_display_point(display_snapshot);
19530                let end = range.end.to_display_point(display_snapshot);
19531                results.push((start..end, color))
19532            }
19533        }
19534        results
19535    }
19536
19537    pub fn background_highlight_row_ranges<T: 'static>(
19538        &self,
19539        search_range: Range<Anchor>,
19540        display_snapshot: &DisplaySnapshot,
19541        count: usize,
19542    ) -> Vec<RangeInclusive<DisplayPoint>> {
19543        let mut results = Vec::new();
19544        let Some((_, ranges)) = self
19545            .background_highlights
19546            .get(&HighlightKey::Type(TypeId::of::<T>()))
19547        else {
19548            return vec![];
19549        };
19550
19551        let start_ix = match ranges.binary_search_by(|probe| {
19552            let cmp = probe
19553                .end
19554                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19555            if cmp.is_gt() {
19556                Ordering::Greater
19557            } else {
19558                Ordering::Less
19559            }
19560        }) {
19561            Ok(i) | Err(i) => i,
19562        };
19563        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19564            if let (Some(start_display), Some(end_display)) = (start, end) {
19565                results.push(
19566                    start_display.to_display_point(display_snapshot)
19567                        ..=end_display.to_display_point(display_snapshot),
19568                );
19569            }
19570        };
19571        let mut start_row: Option<Point> = None;
19572        let mut end_row: Option<Point> = None;
19573        if ranges.len() > count {
19574            return Vec::new();
19575        }
19576        for range in &ranges[start_ix..] {
19577            if range
19578                .start
19579                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19580                .is_ge()
19581            {
19582                break;
19583            }
19584            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19585            if let Some(current_row) = &end_row {
19586                if end.row == current_row.row {
19587                    continue;
19588                }
19589            }
19590            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19591            if start_row.is_none() {
19592                assert_eq!(end_row, None);
19593                start_row = Some(start);
19594                end_row = Some(end);
19595                continue;
19596            }
19597            if let Some(current_end) = end_row.as_mut() {
19598                if start.row > current_end.row + 1 {
19599                    push_region(start_row, end_row);
19600                    start_row = Some(start);
19601                    end_row = Some(end);
19602                } else {
19603                    // Merge two hunks.
19604                    *current_end = end;
19605                }
19606            } else {
19607                unreachable!();
19608            }
19609        }
19610        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19611        push_region(start_row, end_row);
19612        results
19613    }
19614
19615    pub fn gutter_highlights_in_range(
19616        &self,
19617        search_range: Range<Anchor>,
19618        display_snapshot: &DisplaySnapshot,
19619        cx: &App,
19620    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19621        let mut results = Vec::new();
19622        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19623            let color = color_fetcher(cx);
19624            let start_ix = match ranges.binary_search_by(|probe| {
19625                let cmp = probe
19626                    .end
19627                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19628                if cmp.is_gt() {
19629                    Ordering::Greater
19630                } else {
19631                    Ordering::Less
19632                }
19633            }) {
19634                Ok(i) | Err(i) => i,
19635            };
19636            for range in &ranges[start_ix..] {
19637                if range
19638                    .start
19639                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19640                    .is_ge()
19641                {
19642                    break;
19643                }
19644
19645                let start = range.start.to_display_point(display_snapshot);
19646                let end = range.end.to_display_point(display_snapshot);
19647                results.push((start..end, color))
19648            }
19649        }
19650        results
19651    }
19652
19653    /// Get the text ranges corresponding to the redaction query
19654    pub fn redacted_ranges(
19655        &self,
19656        search_range: Range<Anchor>,
19657        display_snapshot: &DisplaySnapshot,
19658        cx: &App,
19659    ) -> Vec<Range<DisplayPoint>> {
19660        display_snapshot
19661            .buffer_snapshot
19662            .redacted_ranges(search_range, |file| {
19663                if let Some(file) = file {
19664                    file.is_private()
19665                        && EditorSettings::get(
19666                            Some(SettingsLocation {
19667                                worktree_id: file.worktree_id(cx),
19668                                path: file.path().as_ref(),
19669                            }),
19670                            cx,
19671                        )
19672                        .redact_private_values
19673                } else {
19674                    false
19675                }
19676            })
19677            .map(|range| {
19678                range.start.to_display_point(display_snapshot)
19679                    ..range.end.to_display_point(display_snapshot)
19680            })
19681            .collect()
19682    }
19683
19684    pub fn highlight_text_key<T: 'static>(
19685        &mut self,
19686        key: usize,
19687        ranges: Vec<Range<Anchor>>,
19688        style: HighlightStyle,
19689        cx: &mut Context<Self>,
19690    ) {
19691        self.display_map.update(cx, |map, _| {
19692            map.highlight_text(
19693                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19694                ranges,
19695                style,
19696            );
19697        });
19698        cx.notify();
19699    }
19700
19701    pub fn highlight_text<T: 'static>(
19702        &mut self,
19703        ranges: Vec<Range<Anchor>>,
19704        style: HighlightStyle,
19705        cx: &mut Context<Self>,
19706    ) {
19707        self.display_map.update(cx, |map, _| {
19708            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19709        });
19710        cx.notify();
19711    }
19712
19713    pub(crate) fn highlight_inlays<T: 'static>(
19714        &mut self,
19715        highlights: Vec<InlayHighlight>,
19716        style: HighlightStyle,
19717        cx: &mut Context<Self>,
19718    ) {
19719        self.display_map.update(cx, |map, _| {
19720            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19721        });
19722        cx.notify();
19723    }
19724
19725    pub fn text_highlights<'a, T: 'static>(
19726        &'a self,
19727        cx: &'a App,
19728    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19729        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19730    }
19731
19732    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19733        let cleared = self
19734            .display_map
19735            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19736        if cleared {
19737            cx.notify();
19738        }
19739    }
19740
19741    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19742        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19743            && self.focus_handle.is_focused(window)
19744    }
19745
19746    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19747        self.show_cursor_when_unfocused = is_enabled;
19748        cx.notify();
19749    }
19750
19751    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19752        cx.notify();
19753    }
19754
19755    fn on_debug_session_event(
19756        &mut self,
19757        _session: Entity<Session>,
19758        event: &SessionEvent,
19759        cx: &mut Context<Self>,
19760    ) {
19761        match event {
19762            SessionEvent::InvalidateInlineValue => {
19763                self.refresh_inline_values(cx);
19764            }
19765            _ => {}
19766        }
19767    }
19768
19769    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19770        let Some(project) = self.project.clone() else {
19771            return;
19772        };
19773
19774        if !self.inline_value_cache.enabled {
19775            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19776            self.splice_inlays(&inlays, Vec::new(), cx);
19777            return;
19778        }
19779
19780        let current_execution_position = self
19781            .highlighted_rows
19782            .get(&TypeId::of::<ActiveDebugLine>())
19783            .and_then(|lines| lines.last().map(|line| line.range.end));
19784
19785        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19786            let inline_values = editor
19787                .update(cx, |editor, cx| {
19788                    let Some(current_execution_position) = current_execution_position else {
19789                        return Some(Task::ready(Ok(Vec::new())));
19790                    };
19791
19792                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19793                        let snapshot = buffer.snapshot(cx);
19794
19795                        let excerpt = snapshot.excerpt_containing(
19796                            current_execution_position..current_execution_position,
19797                        )?;
19798
19799                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19800                    })?;
19801
19802                    let range =
19803                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19804
19805                    project.inline_values(buffer, range, cx)
19806                })
19807                .ok()
19808                .flatten()?
19809                .await
19810                .context("refreshing debugger inlays")
19811                .log_err()?;
19812
19813            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19814
19815            for (buffer_id, inline_value) in inline_values
19816                .into_iter()
19817                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19818            {
19819                buffer_inline_values
19820                    .entry(buffer_id)
19821                    .or_default()
19822                    .push(inline_value);
19823            }
19824
19825            editor
19826                .update(cx, |editor, cx| {
19827                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19828                    let mut new_inlays = Vec::default();
19829
19830                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19831                        let buffer_id = buffer_snapshot.remote_id();
19832                        buffer_inline_values
19833                            .get(&buffer_id)
19834                            .into_iter()
19835                            .flatten()
19836                            .for_each(|hint| {
19837                                let inlay = Inlay::debugger(
19838                                    post_inc(&mut editor.next_inlay_id),
19839                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19840                                    hint.text(),
19841                                );
19842                                if !inlay.text.chars().contains(&'\n') {
19843                                    new_inlays.push(inlay);
19844                                }
19845                            });
19846                    }
19847
19848                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19849                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19850
19851                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19852                })
19853                .ok()?;
19854            Some(())
19855        });
19856    }
19857
19858    fn on_buffer_event(
19859        &mut self,
19860        multibuffer: &Entity<MultiBuffer>,
19861        event: &multi_buffer::Event,
19862        window: &mut Window,
19863        cx: &mut Context<Self>,
19864    ) {
19865        match event {
19866            multi_buffer::Event::Edited {
19867                singleton_buffer_edited,
19868                edited_buffer,
19869            } => {
19870                self.scrollbar_marker_state.dirty = true;
19871                self.active_indent_guides_state.dirty = true;
19872                self.refresh_active_diagnostics(cx);
19873                self.refresh_code_actions(window, cx);
19874                self.refresh_selected_text_highlights(true, window, cx);
19875                self.refresh_single_line_folds(window, cx);
19876                refresh_matching_bracket_highlights(self, window, cx);
19877                if self.has_active_inline_completion() {
19878                    self.update_visible_inline_completion(window, cx);
19879                }
19880                if let Some(project) = self.project.as_ref() {
19881                    if let Some(edited_buffer) = edited_buffer {
19882                        project.update(cx, |project, cx| {
19883                            self.registered_buffers
19884                                .entry(edited_buffer.read(cx).remote_id())
19885                                .or_insert_with(|| {
19886                                    project
19887                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19888                                });
19889                        });
19890                    }
19891                }
19892                cx.emit(EditorEvent::BufferEdited);
19893                cx.emit(SearchEvent::MatchesInvalidated);
19894
19895                if let Some(buffer) = edited_buffer {
19896                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
19897                }
19898
19899                if *singleton_buffer_edited {
19900                    if let Some(buffer) = edited_buffer {
19901                        if buffer.read(cx).file().is_none() {
19902                            cx.emit(EditorEvent::TitleChanged);
19903                        }
19904                    }
19905                    if let Some(project) = &self.project {
19906                        #[allow(clippy::mutable_key_type)]
19907                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19908                            multibuffer
19909                                .all_buffers()
19910                                .into_iter()
19911                                .filter_map(|buffer| {
19912                                    buffer.update(cx, |buffer, cx| {
19913                                        let language = buffer.language()?;
19914                                        let should_discard = project.update(cx, |project, cx| {
19915                                            project.is_local()
19916                                                && !project.has_language_servers_for(buffer, cx)
19917                                        });
19918                                        should_discard.not().then_some(language.clone())
19919                                    })
19920                                })
19921                                .collect::<HashSet<_>>()
19922                        });
19923                        if !languages_affected.is_empty() {
19924                            self.refresh_inlay_hints(
19925                                InlayHintRefreshReason::BufferEdited(languages_affected),
19926                                cx,
19927                            );
19928                        }
19929                    }
19930                }
19931
19932                let Some(project) = &self.project else { return };
19933                let (telemetry, is_via_ssh) = {
19934                    let project = project.read(cx);
19935                    let telemetry = project.client().telemetry().clone();
19936                    let is_via_ssh = project.is_via_ssh();
19937                    (telemetry, is_via_ssh)
19938                };
19939                refresh_linked_ranges(self, window, cx);
19940                telemetry.log_edit_event("editor", is_via_ssh);
19941            }
19942            multi_buffer::Event::ExcerptsAdded {
19943                buffer,
19944                predecessor,
19945                excerpts,
19946            } => {
19947                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19948                let buffer_id = buffer.read(cx).remote_id();
19949                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19950                    if let Some(project) = &self.project {
19951                        update_uncommitted_diff_for_buffer(
19952                            cx.entity(),
19953                            project,
19954                            [buffer.clone()],
19955                            self.buffer.clone(),
19956                            cx,
19957                        )
19958                        .detach();
19959                    }
19960                }
19961                self.update_lsp_data(false, Some(buffer_id), window, cx);
19962                cx.emit(EditorEvent::ExcerptsAdded {
19963                    buffer: buffer.clone(),
19964                    predecessor: *predecessor,
19965                    excerpts: excerpts.clone(),
19966                });
19967                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19968            }
19969            multi_buffer::Event::ExcerptsRemoved {
19970                ids,
19971                removed_buffer_ids,
19972            } => {
19973                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19974                let buffer = self.buffer.read(cx);
19975                self.registered_buffers
19976                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19977                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19978                cx.emit(EditorEvent::ExcerptsRemoved {
19979                    ids: ids.clone(),
19980                    removed_buffer_ids: removed_buffer_ids.clone(),
19981                });
19982            }
19983            multi_buffer::Event::ExcerptsEdited {
19984                excerpt_ids,
19985                buffer_ids,
19986            } => {
19987                self.display_map.update(cx, |map, cx| {
19988                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19989                });
19990                cx.emit(EditorEvent::ExcerptsEdited {
19991                    ids: excerpt_ids.clone(),
19992                });
19993            }
19994            multi_buffer::Event::ExcerptsExpanded { ids } => {
19995                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19996                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19997            }
19998            multi_buffer::Event::Reparsed(buffer_id) => {
19999                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20000                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20001
20002                cx.emit(EditorEvent::Reparsed(*buffer_id));
20003            }
20004            multi_buffer::Event::DiffHunksToggled => {
20005                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20006            }
20007            multi_buffer::Event::LanguageChanged(buffer_id) => {
20008                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20009                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20010                cx.emit(EditorEvent::Reparsed(*buffer_id));
20011                cx.notify();
20012            }
20013            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20014            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20015            multi_buffer::Event::FileHandleChanged
20016            | multi_buffer::Event::Reloaded
20017            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20018            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
20019            multi_buffer::Event::DiagnosticsUpdated => {
20020                self.update_diagnostics_state(window, cx);
20021            }
20022            _ => {}
20023        };
20024    }
20025
20026    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20027        if !self.diagnostics_enabled() {
20028            return;
20029        }
20030        self.refresh_active_diagnostics(cx);
20031        self.refresh_inline_diagnostics(true, window, cx);
20032        self.scrollbar_marker_state.dirty = true;
20033        cx.notify();
20034    }
20035
20036    pub fn start_temporary_diff_override(&mut self) {
20037        self.load_diff_task.take();
20038        self.temporary_diff_override = true;
20039    }
20040
20041    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20042        self.temporary_diff_override = false;
20043        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20044        self.buffer.update(cx, |buffer, cx| {
20045            buffer.set_all_diff_hunks_collapsed(cx);
20046        });
20047
20048        if let Some(project) = self.project.clone() {
20049            self.load_diff_task = Some(
20050                update_uncommitted_diff_for_buffer(
20051                    cx.entity(),
20052                    &project,
20053                    self.buffer.read(cx).all_buffers(),
20054                    self.buffer.clone(),
20055                    cx,
20056                )
20057                .shared(),
20058            );
20059        }
20060    }
20061
20062    fn on_display_map_changed(
20063        &mut self,
20064        _: Entity<DisplayMap>,
20065        _: &mut Window,
20066        cx: &mut Context<Self>,
20067    ) {
20068        cx.notify();
20069    }
20070
20071    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20072        if self.diagnostics_enabled() {
20073            let new_severity = EditorSettings::get_global(cx)
20074                .diagnostics_max_severity
20075                .unwrap_or(DiagnosticSeverity::Hint);
20076            self.set_max_diagnostics_severity(new_severity, cx);
20077        }
20078        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20079        self.update_edit_prediction_settings(cx);
20080        self.refresh_inline_completion(true, false, window, cx);
20081        self.refresh_inline_values(cx);
20082        self.refresh_inlay_hints(
20083            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20084                self.selections.newest_anchor().head(),
20085                &self.buffer.read(cx).snapshot(cx),
20086                cx,
20087            )),
20088            cx,
20089        );
20090
20091        let old_cursor_shape = self.cursor_shape;
20092
20093        {
20094            let editor_settings = EditorSettings::get_global(cx);
20095            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20096            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20097            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20098            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20099        }
20100
20101        if old_cursor_shape != self.cursor_shape {
20102            cx.emit(EditorEvent::CursorShapeChanged);
20103        }
20104
20105        let project_settings = ProjectSettings::get_global(cx);
20106        self.serialize_dirty_buffers =
20107            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20108
20109        if self.mode.is_full() {
20110            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20111            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20112            if self.show_inline_diagnostics != show_inline_diagnostics {
20113                self.show_inline_diagnostics = show_inline_diagnostics;
20114                self.refresh_inline_diagnostics(false, window, cx);
20115            }
20116
20117            if self.git_blame_inline_enabled != inline_blame_enabled {
20118                self.toggle_git_blame_inline_internal(false, window, cx);
20119            }
20120
20121            let minimap_settings = EditorSettings::get_global(cx).minimap;
20122            if self.minimap_visibility != MinimapVisibility::Disabled {
20123                if self.minimap_visibility.settings_visibility()
20124                    != minimap_settings.minimap_enabled()
20125                {
20126                    self.set_minimap_visibility(
20127                        MinimapVisibility::for_mode(self.mode(), cx),
20128                        window,
20129                        cx,
20130                    );
20131                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20132                    minimap_entity.update(cx, |minimap_editor, cx| {
20133                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20134                    })
20135                }
20136            }
20137        }
20138
20139        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20140            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20141        }) {
20142            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20143                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20144            }
20145            self.refresh_colors(false, None, window, cx);
20146        }
20147
20148        cx.notify();
20149    }
20150
20151    pub fn set_searchable(&mut self, searchable: bool) {
20152        self.searchable = searchable;
20153    }
20154
20155    pub fn searchable(&self) -> bool {
20156        self.searchable
20157    }
20158
20159    fn open_proposed_changes_editor(
20160        &mut self,
20161        _: &OpenProposedChangesEditor,
20162        window: &mut Window,
20163        cx: &mut Context<Self>,
20164    ) {
20165        let Some(workspace) = self.workspace() else {
20166            cx.propagate();
20167            return;
20168        };
20169
20170        let selections = self.selections.all::<usize>(cx);
20171        let multi_buffer = self.buffer.read(cx);
20172        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20173        let mut new_selections_by_buffer = HashMap::default();
20174        for selection in selections {
20175            for (buffer, range, _) in
20176                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20177            {
20178                let mut range = range.to_point(buffer);
20179                range.start.column = 0;
20180                range.end.column = buffer.line_len(range.end.row);
20181                new_selections_by_buffer
20182                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20183                    .or_insert(Vec::new())
20184                    .push(range)
20185            }
20186        }
20187
20188        let proposed_changes_buffers = new_selections_by_buffer
20189            .into_iter()
20190            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20191            .collect::<Vec<_>>();
20192        let proposed_changes_editor = cx.new(|cx| {
20193            ProposedChangesEditor::new(
20194                "Proposed changes",
20195                proposed_changes_buffers,
20196                self.project.clone(),
20197                window,
20198                cx,
20199            )
20200        });
20201
20202        window.defer(cx, move |window, cx| {
20203            workspace.update(cx, |workspace, cx| {
20204                workspace.active_pane().update(cx, |pane, cx| {
20205                    pane.add_item(
20206                        Box::new(proposed_changes_editor),
20207                        true,
20208                        true,
20209                        None,
20210                        window,
20211                        cx,
20212                    );
20213                });
20214            });
20215        });
20216    }
20217
20218    pub fn open_excerpts_in_split(
20219        &mut self,
20220        _: &OpenExcerptsSplit,
20221        window: &mut Window,
20222        cx: &mut Context<Self>,
20223    ) {
20224        self.open_excerpts_common(None, true, window, cx)
20225    }
20226
20227    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20228        self.open_excerpts_common(None, false, window, cx)
20229    }
20230
20231    fn open_excerpts_common(
20232        &mut self,
20233        jump_data: Option<JumpData>,
20234        split: bool,
20235        window: &mut Window,
20236        cx: &mut Context<Self>,
20237    ) {
20238        let Some(workspace) = self.workspace() else {
20239            cx.propagate();
20240            return;
20241        };
20242
20243        if self.buffer.read(cx).is_singleton() {
20244            cx.propagate();
20245            return;
20246        }
20247
20248        let mut new_selections_by_buffer = HashMap::default();
20249        match &jump_data {
20250            Some(JumpData::MultiBufferPoint {
20251                excerpt_id,
20252                position,
20253                anchor,
20254                line_offset_from_top,
20255            }) => {
20256                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20257                if let Some(buffer) = multi_buffer_snapshot
20258                    .buffer_id_for_excerpt(*excerpt_id)
20259                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20260                {
20261                    let buffer_snapshot = buffer.read(cx).snapshot();
20262                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20263                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20264                    } else {
20265                        buffer_snapshot.clip_point(*position, Bias::Left)
20266                    };
20267                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20268                    new_selections_by_buffer.insert(
20269                        buffer,
20270                        (
20271                            vec![jump_to_offset..jump_to_offset],
20272                            Some(*line_offset_from_top),
20273                        ),
20274                    );
20275                }
20276            }
20277            Some(JumpData::MultiBufferRow {
20278                row,
20279                line_offset_from_top,
20280            }) => {
20281                let point = MultiBufferPoint::new(row.0, 0);
20282                if let Some((buffer, buffer_point, _)) =
20283                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20284                {
20285                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20286                    new_selections_by_buffer
20287                        .entry(buffer)
20288                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20289                        .0
20290                        .push(buffer_offset..buffer_offset)
20291                }
20292            }
20293            None => {
20294                let selections = self.selections.all::<usize>(cx);
20295                let multi_buffer = self.buffer.read(cx);
20296                for selection in selections {
20297                    for (snapshot, range, _, anchor) in multi_buffer
20298                        .snapshot(cx)
20299                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20300                    {
20301                        if let Some(anchor) = anchor {
20302                            // selection is in a deleted hunk
20303                            let Some(buffer_id) = anchor.buffer_id else {
20304                                continue;
20305                            };
20306                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
20307                                continue;
20308                            };
20309                            let offset = text::ToOffset::to_offset(
20310                                &anchor.text_anchor,
20311                                &buffer_handle.read(cx).snapshot(),
20312                            );
20313                            let range = offset..offset;
20314                            new_selections_by_buffer
20315                                .entry(buffer_handle)
20316                                .or_insert((Vec::new(), None))
20317                                .0
20318                                .push(range)
20319                        } else {
20320                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20321                            else {
20322                                continue;
20323                            };
20324                            new_selections_by_buffer
20325                                .entry(buffer_handle)
20326                                .or_insert((Vec::new(), None))
20327                                .0
20328                                .push(range)
20329                        }
20330                    }
20331                }
20332            }
20333        }
20334
20335        new_selections_by_buffer
20336            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20337
20338        if new_selections_by_buffer.is_empty() {
20339            return;
20340        }
20341
20342        // We defer the pane interaction because we ourselves are a workspace item
20343        // and activating a new item causes the pane to call a method on us reentrantly,
20344        // which panics if we're on the stack.
20345        window.defer(cx, move |window, cx| {
20346            workspace.update(cx, |workspace, cx| {
20347                let pane = if split {
20348                    workspace.adjacent_pane(window, cx)
20349                } else {
20350                    workspace.active_pane().clone()
20351                };
20352
20353                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20354                    let editor = buffer
20355                        .read(cx)
20356                        .file()
20357                        .is_none()
20358                        .then(|| {
20359                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20360                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20361                            // Instead, we try to activate the existing editor in the pane first.
20362                            let (editor, pane_item_index) =
20363                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20364                                    let editor = item.downcast::<Editor>()?;
20365                                    let singleton_buffer =
20366                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20367                                    if singleton_buffer == buffer {
20368                                        Some((editor, i))
20369                                    } else {
20370                                        None
20371                                    }
20372                                })?;
20373                            pane.update(cx, |pane, cx| {
20374                                pane.activate_item(pane_item_index, true, true, window, cx)
20375                            });
20376                            Some(editor)
20377                        })
20378                        .flatten()
20379                        .unwrap_or_else(|| {
20380                            workspace.open_project_item::<Self>(
20381                                pane.clone(),
20382                                buffer,
20383                                true,
20384                                true,
20385                                window,
20386                                cx,
20387                            )
20388                        });
20389
20390                    editor.update(cx, |editor, cx| {
20391                        let autoscroll = match scroll_offset {
20392                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20393                            None => Autoscroll::newest(),
20394                        };
20395                        let nav_history = editor.nav_history.take();
20396                        editor.change_selections(
20397                            SelectionEffects::scroll(autoscroll),
20398                            window,
20399                            cx,
20400                            |s| {
20401                                s.select_ranges(ranges);
20402                            },
20403                        );
20404                        editor.nav_history = nav_history;
20405                    });
20406                }
20407            })
20408        });
20409    }
20410
20411    // For now, don't allow opening excerpts in buffers that aren't backed by
20412    // regular project files.
20413    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20414        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
20415    }
20416
20417    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20418        let snapshot = self.buffer.read(cx).read(cx);
20419        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20420        Some(
20421            ranges
20422                .iter()
20423                .map(move |range| {
20424                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20425                })
20426                .collect(),
20427        )
20428    }
20429
20430    fn selection_replacement_ranges(
20431        &self,
20432        range: Range<OffsetUtf16>,
20433        cx: &mut App,
20434    ) -> Vec<Range<OffsetUtf16>> {
20435        let selections = self.selections.all::<OffsetUtf16>(cx);
20436        let newest_selection = selections
20437            .iter()
20438            .max_by_key(|selection| selection.id)
20439            .unwrap();
20440        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20441        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20442        let snapshot = self.buffer.read(cx).read(cx);
20443        selections
20444            .into_iter()
20445            .map(|mut selection| {
20446                selection.start.0 =
20447                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20448                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20449                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20450                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20451            })
20452            .collect()
20453    }
20454
20455    fn report_editor_event(
20456        &self,
20457        event_type: &'static str,
20458        file_extension: Option<String>,
20459        cx: &App,
20460    ) {
20461        if cfg!(any(test, feature = "test-support")) {
20462            return;
20463        }
20464
20465        let Some(project) = &self.project else { return };
20466
20467        // If None, we are in a file without an extension
20468        let file = self
20469            .buffer
20470            .read(cx)
20471            .as_singleton()
20472            .and_then(|b| b.read(cx).file());
20473        let file_extension = file_extension.or(file
20474            .as_ref()
20475            .and_then(|file| Path::new(file.file_name(cx)).extension())
20476            .and_then(|e| e.to_str())
20477            .map(|a| a.to_string()));
20478
20479        let vim_mode = vim_enabled(cx);
20480
20481        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20482        let copilot_enabled = edit_predictions_provider
20483            == language::language_settings::EditPredictionProvider::Copilot;
20484        let copilot_enabled_for_language = self
20485            .buffer
20486            .read(cx)
20487            .language_settings(cx)
20488            .show_edit_predictions;
20489
20490        let project = project.read(cx);
20491        telemetry::event!(
20492            event_type,
20493            file_extension,
20494            vim_mode,
20495            copilot_enabled,
20496            copilot_enabled_for_language,
20497            edit_predictions_provider,
20498            is_via_ssh = project.is_via_ssh(),
20499        );
20500    }
20501
20502    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20503    /// with each line being an array of {text, highlight} objects.
20504    fn copy_highlight_json(
20505        &mut self,
20506        _: &CopyHighlightJson,
20507        window: &mut Window,
20508        cx: &mut Context<Self>,
20509    ) {
20510        #[derive(Serialize)]
20511        struct Chunk<'a> {
20512            text: String,
20513            highlight: Option<&'a str>,
20514        }
20515
20516        let snapshot = self.buffer.read(cx).snapshot(cx);
20517        let range = self
20518            .selected_text_range(false, window, cx)
20519            .and_then(|selection| {
20520                if selection.range.is_empty() {
20521                    None
20522                } else {
20523                    Some(selection.range)
20524                }
20525            })
20526            .unwrap_or_else(|| 0..snapshot.len());
20527
20528        let chunks = snapshot.chunks(range, true);
20529        let mut lines = Vec::new();
20530        let mut line: VecDeque<Chunk> = VecDeque::new();
20531
20532        let Some(style) = self.style.as_ref() else {
20533            return;
20534        };
20535
20536        for chunk in chunks {
20537            let highlight = chunk
20538                .syntax_highlight_id
20539                .and_then(|id| id.name(&style.syntax));
20540            let mut chunk_lines = chunk.text.split('\n').peekable();
20541            while let Some(text) = chunk_lines.next() {
20542                let mut merged_with_last_token = false;
20543                if let Some(last_token) = line.back_mut() {
20544                    if last_token.highlight == highlight {
20545                        last_token.text.push_str(text);
20546                        merged_with_last_token = true;
20547                    }
20548                }
20549
20550                if !merged_with_last_token {
20551                    line.push_back(Chunk {
20552                        text: text.into(),
20553                        highlight,
20554                    });
20555                }
20556
20557                if chunk_lines.peek().is_some() {
20558                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20559                        line.pop_front();
20560                    }
20561                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20562                        line.pop_back();
20563                    }
20564
20565                    lines.push(mem::take(&mut line));
20566                }
20567            }
20568        }
20569
20570        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20571            return;
20572        };
20573        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20574    }
20575
20576    pub fn open_context_menu(
20577        &mut self,
20578        _: &OpenContextMenu,
20579        window: &mut Window,
20580        cx: &mut Context<Self>,
20581    ) {
20582        self.request_autoscroll(Autoscroll::newest(), cx);
20583        let position = self.selections.newest_display(cx).start;
20584        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20585    }
20586
20587    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20588        &self.inlay_hint_cache
20589    }
20590
20591    pub fn replay_insert_event(
20592        &mut self,
20593        text: &str,
20594        relative_utf16_range: Option<Range<isize>>,
20595        window: &mut Window,
20596        cx: &mut Context<Self>,
20597    ) {
20598        if !self.input_enabled {
20599            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20600            return;
20601        }
20602        if let Some(relative_utf16_range) = relative_utf16_range {
20603            let selections = self.selections.all::<OffsetUtf16>(cx);
20604            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20605                let new_ranges = selections.into_iter().map(|range| {
20606                    let start = OffsetUtf16(
20607                        range
20608                            .head()
20609                            .0
20610                            .saturating_add_signed(relative_utf16_range.start),
20611                    );
20612                    let end = OffsetUtf16(
20613                        range
20614                            .head()
20615                            .0
20616                            .saturating_add_signed(relative_utf16_range.end),
20617                    );
20618                    start..end
20619                });
20620                s.select_ranges(new_ranges);
20621            });
20622        }
20623
20624        self.handle_input(text, window, cx);
20625    }
20626
20627    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20628        let Some(provider) = self.semantics_provider.as_ref() else {
20629            return false;
20630        };
20631
20632        let mut supports = false;
20633        self.buffer().update(cx, |this, cx| {
20634            this.for_each_buffer(|buffer| {
20635                supports |= provider.supports_inlay_hints(buffer, cx);
20636            });
20637        });
20638
20639        supports
20640    }
20641
20642    pub fn is_focused(&self, window: &Window) -> bool {
20643        self.focus_handle.is_focused(window)
20644    }
20645
20646    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20647        cx.emit(EditorEvent::Focused);
20648
20649        if let Some(descendant) = self
20650            .last_focused_descendant
20651            .take()
20652            .and_then(|descendant| descendant.upgrade())
20653        {
20654            window.focus(&descendant);
20655        } else {
20656            if let Some(blame) = self.blame.as_ref() {
20657                blame.update(cx, GitBlame::focus)
20658            }
20659
20660            self.blink_manager.update(cx, BlinkManager::enable);
20661            self.show_cursor_names(window, cx);
20662            self.buffer.update(cx, |buffer, cx| {
20663                buffer.finalize_last_transaction(cx);
20664                if self.leader_id.is_none() {
20665                    buffer.set_active_selections(
20666                        &self.selections.disjoint_anchors(),
20667                        self.selections.line_mode,
20668                        self.cursor_shape,
20669                        cx,
20670                    );
20671                }
20672            });
20673        }
20674    }
20675
20676    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20677        cx.emit(EditorEvent::FocusedIn)
20678    }
20679
20680    fn handle_focus_out(
20681        &mut self,
20682        event: FocusOutEvent,
20683        _window: &mut Window,
20684        cx: &mut Context<Self>,
20685    ) {
20686        if event.blurred != self.focus_handle {
20687            self.last_focused_descendant = Some(event.blurred);
20688        }
20689        self.selection_drag_state = SelectionDragState::None;
20690        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20691    }
20692
20693    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20694        self.blink_manager.update(cx, BlinkManager::disable);
20695        self.buffer
20696            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20697
20698        if let Some(blame) = self.blame.as_ref() {
20699            blame.update(cx, GitBlame::blur)
20700        }
20701        if !self.hover_state.focused(window, cx) {
20702            hide_hover(self, cx);
20703        }
20704        if !self
20705            .context_menu
20706            .borrow()
20707            .as_ref()
20708            .is_some_and(|context_menu| context_menu.focused(window, cx))
20709        {
20710            self.hide_context_menu(window, cx);
20711        }
20712        self.discard_inline_completion(false, cx);
20713        cx.emit(EditorEvent::Blurred);
20714        cx.notify();
20715    }
20716
20717    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20718        let mut pending: String = window
20719            .pending_input_keystrokes()
20720            .into_iter()
20721            .flatten()
20722            .filter_map(|keystroke| {
20723                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20724                    keystroke.key_char.clone()
20725                } else {
20726                    None
20727                }
20728            })
20729            .collect();
20730
20731        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20732            pending = "".to_string();
20733        }
20734
20735        let existing_pending = self
20736            .text_highlights::<PendingInput>(cx)
20737            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
20738        if existing_pending.is_none() && pending.is_empty() {
20739            return;
20740        }
20741        let transaction =
20742            self.transact(window, cx, |this, window, cx| {
20743                let selections = this.selections.all::<usize>(cx);
20744                let edits = selections
20745                    .iter()
20746                    .map(|selection| (selection.end..selection.end, pending.clone()));
20747                this.edit(edits, cx);
20748                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20749                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20750                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20751                    }));
20752                });
20753                if let Some(existing_ranges) = existing_pending {
20754                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20755                    this.edit(edits, cx);
20756                }
20757            });
20758
20759        let snapshot = self.snapshot(window, cx);
20760        let ranges = self
20761            .selections
20762            .all::<usize>(cx)
20763            .into_iter()
20764            .map(|selection| {
20765                snapshot.buffer_snapshot.anchor_after(selection.end)
20766                    ..snapshot
20767                        .buffer_snapshot
20768                        .anchor_before(selection.end + pending.len())
20769            })
20770            .collect();
20771
20772        if pending.is_empty() {
20773            self.clear_highlights::<PendingInput>(cx);
20774        } else {
20775            self.highlight_text::<PendingInput>(
20776                ranges,
20777                HighlightStyle {
20778                    underline: Some(UnderlineStyle {
20779                        thickness: px(1.),
20780                        color: None,
20781                        wavy: false,
20782                    }),
20783                    ..Default::default()
20784                },
20785                cx,
20786            );
20787        }
20788
20789        self.ime_transaction = self.ime_transaction.or(transaction);
20790        if let Some(transaction) = self.ime_transaction {
20791            self.buffer.update(cx, |buffer, cx| {
20792                buffer.group_until_transaction(transaction, cx);
20793            });
20794        }
20795
20796        if self.text_highlights::<PendingInput>(cx).is_none() {
20797            self.ime_transaction.take();
20798        }
20799    }
20800
20801    pub fn register_action_renderer(
20802        &mut self,
20803        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20804    ) -> Subscription {
20805        let id = self.next_editor_action_id.post_inc();
20806        self.editor_actions
20807            .borrow_mut()
20808            .insert(id, Box::new(listener));
20809
20810        let editor_actions = self.editor_actions.clone();
20811        Subscription::new(move || {
20812            editor_actions.borrow_mut().remove(&id);
20813        })
20814    }
20815
20816    pub fn register_action<A: Action>(
20817        &mut self,
20818        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20819    ) -> Subscription {
20820        let id = self.next_editor_action_id.post_inc();
20821        let listener = Arc::new(listener);
20822        self.editor_actions.borrow_mut().insert(
20823            id,
20824            Box::new(move |_, window, _| {
20825                let listener = listener.clone();
20826                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20827                    let action = action.downcast_ref().unwrap();
20828                    if phase == DispatchPhase::Bubble {
20829                        listener(action, window, cx)
20830                    }
20831                })
20832            }),
20833        );
20834
20835        let editor_actions = self.editor_actions.clone();
20836        Subscription::new(move || {
20837            editor_actions.borrow_mut().remove(&id);
20838        })
20839    }
20840
20841    pub fn file_header_size(&self) -> u32 {
20842        FILE_HEADER_HEIGHT
20843    }
20844
20845    pub fn restore(
20846        &mut self,
20847        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20848        window: &mut Window,
20849        cx: &mut Context<Self>,
20850    ) {
20851        let workspace = self.workspace();
20852        let project = self.project.as_ref();
20853        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20854            let mut tasks = Vec::new();
20855            for (buffer_id, changes) in revert_changes {
20856                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20857                    buffer.update(cx, |buffer, cx| {
20858                        buffer.edit(
20859                            changes
20860                                .into_iter()
20861                                .map(|(range, text)| (range, text.to_string())),
20862                            None,
20863                            cx,
20864                        );
20865                    });
20866
20867                    if let Some(project) =
20868                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20869                    {
20870                        project.update(cx, |project, cx| {
20871                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20872                        })
20873                    }
20874                }
20875            }
20876            tasks
20877        });
20878        cx.spawn_in(window, async move |_, cx| {
20879            for (buffer, task) in save_tasks {
20880                let result = task.await;
20881                if result.is_err() {
20882                    let Some(path) = buffer
20883                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20884                        .ok()
20885                    else {
20886                        continue;
20887                    };
20888                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20889                        let Some(task) = cx
20890                            .update_window_entity(&workspace, |workspace, window, cx| {
20891                                workspace
20892                                    .open_path_preview(path, None, false, false, false, window, cx)
20893                            })
20894                            .ok()
20895                        else {
20896                            continue;
20897                        };
20898                        task.await.log_err();
20899                    }
20900                }
20901            }
20902        })
20903        .detach();
20904        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
20905            selections.refresh()
20906        });
20907    }
20908
20909    pub fn to_pixel_point(
20910        &self,
20911        source: multi_buffer::Anchor,
20912        editor_snapshot: &EditorSnapshot,
20913        window: &mut Window,
20914    ) -> Option<gpui::Point<Pixels>> {
20915        let source_point = source.to_display_point(editor_snapshot);
20916        self.display_to_pixel_point(source_point, editor_snapshot, window)
20917    }
20918
20919    pub fn display_to_pixel_point(
20920        &self,
20921        source: DisplayPoint,
20922        editor_snapshot: &EditorSnapshot,
20923        window: &mut Window,
20924    ) -> Option<gpui::Point<Pixels>> {
20925        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20926        let text_layout_details = self.text_layout_details(window);
20927        let scroll_top = text_layout_details
20928            .scroll_anchor
20929            .scroll_position(editor_snapshot)
20930            .y;
20931
20932        if source.row().as_f32() < scroll_top.floor() {
20933            return None;
20934        }
20935        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20936        let source_y = line_height * (source.row().as_f32() - scroll_top);
20937        Some(gpui::Point::new(source_x, source_y))
20938    }
20939
20940    pub fn has_visible_completions_menu(&self) -> bool {
20941        !self.edit_prediction_preview_is_active()
20942            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20943                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20944            })
20945    }
20946
20947    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20948        if self.mode.is_minimap() {
20949            return;
20950        }
20951        self.addons
20952            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20953    }
20954
20955    pub fn unregister_addon<T: Addon>(&mut self) {
20956        self.addons.remove(&std::any::TypeId::of::<T>());
20957    }
20958
20959    pub fn addon<T: Addon>(&self) -> Option<&T> {
20960        let type_id = std::any::TypeId::of::<T>();
20961        self.addons
20962            .get(&type_id)
20963            .and_then(|item| item.to_any().downcast_ref::<T>())
20964    }
20965
20966    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20967        let type_id = std::any::TypeId::of::<T>();
20968        self.addons
20969            .get_mut(&type_id)
20970            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20971    }
20972
20973    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
20974        let text_layout_details = self.text_layout_details(window);
20975        let style = &text_layout_details.editor_style;
20976        let font_id = window.text_system().resolve_font(&style.text.font());
20977        let font_size = style.text.font_size.to_pixels(window.rem_size());
20978        let line_height = style.text.line_height_in_pixels(window.rem_size());
20979        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20980        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
20981
20982        CharacterDimensions {
20983            em_width,
20984            em_advance,
20985            line_height,
20986        }
20987    }
20988
20989    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20990        self.load_diff_task.clone()
20991    }
20992
20993    fn read_metadata_from_db(
20994        &mut self,
20995        item_id: u64,
20996        workspace_id: WorkspaceId,
20997        window: &mut Window,
20998        cx: &mut Context<Editor>,
20999    ) {
21000        if self.is_singleton(cx)
21001            && !self.mode.is_minimap()
21002            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21003        {
21004            let buffer_snapshot = OnceCell::new();
21005
21006            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
21007                if !folds.is_empty() {
21008                    let snapshot =
21009                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21010                    self.fold_ranges(
21011                        folds
21012                            .into_iter()
21013                            .map(|(start, end)| {
21014                                snapshot.clip_offset(start, Bias::Left)
21015                                    ..snapshot.clip_offset(end, Bias::Right)
21016                            })
21017                            .collect(),
21018                        false,
21019                        window,
21020                        cx,
21021                    );
21022                }
21023            }
21024
21025            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
21026                if !selections.is_empty() {
21027                    let snapshot =
21028                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21029                    // skip adding the initial selection to selection history
21030                    self.selection_history.mode = SelectionHistoryMode::Skipping;
21031                    self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21032                        s.select_ranges(selections.into_iter().map(|(start, end)| {
21033                            snapshot.clip_offset(start, Bias::Left)
21034                                ..snapshot.clip_offset(end, Bias::Right)
21035                        }));
21036                    });
21037                    self.selection_history.mode = SelectionHistoryMode::Normal;
21038                }
21039            };
21040        }
21041
21042        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21043    }
21044
21045    fn update_lsp_data(
21046        &mut self,
21047        ignore_cache: bool,
21048        for_buffer: Option<BufferId>,
21049        window: &mut Window,
21050        cx: &mut Context<'_, Self>,
21051    ) {
21052        self.pull_diagnostics(for_buffer, window, cx);
21053        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21054    }
21055}
21056
21057fn vim_enabled(cx: &App) -> bool {
21058    cx.global::<SettingsStore>()
21059        .raw_user_settings()
21060        .get("vim_mode")
21061        == Some(&serde_json::Value::Bool(true))
21062}
21063
21064fn process_completion_for_edit(
21065    completion: &Completion,
21066    intent: CompletionIntent,
21067    buffer: &Entity<Buffer>,
21068    cursor_position: &text::Anchor,
21069    cx: &mut Context<Editor>,
21070) -> CompletionEdit {
21071    let buffer = buffer.read(cx);
21072    let buffer_snapshot = buffer.snapshot();
21073    let (snippet, new_text) = if completion.is_snippet() {
21074        // Workaround for typescript language server issues so that methods don't expand within
21075        // strings and functions with type expressions. The previous point is used because the query
21076        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21077        let mut snippet_source = completion.new_text.clone();
21078        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21079        previous_point.column = previous_point.column.saturating_sub(1);
21080        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
21081            if scope.prefers_label_for_snippet_in_completion() {
21082                if let Some(label) = completion.label() {
21083                    if matches!(
21084                        completion.kind(),
21085                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21086                    ) {
21087                        snippet_source = label;
21088                    }
21089                }
21090            }
21091        }
21092        match Snippet::parse(&snippet_source).log_err() {
21093            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21094            None => (None, completion.new_text.clone()),
21095        }
21096    } else {
21097        (None, completion.new_text.clone())
21098    };
21099
21100    let mut range_to_replace = {
21101        let replace_range = &completion.replace_range;
21102        if let CompletionSource::Lsp {
21103            insert_range: Some(insert_range),
21104            ..
21105        } = &completion.source
21106        {
21107            debug_assert_eq!(
21108                insert_range.start, replace_range.start,
21109                "insert_range and replace_range should start at the same position"
21110            );
21111            debug_assert!(
21112                insert_range
21113                    .start
21114                    .cmp(&cursor_position, &buffer_snapshot)
21115                    .is_le(),
21116                "insert_range should start before or at cursor position"
21117            );
21118            debug_assert!(
21119                replace_range
21120                    .start
21121                    .cmp(&cursor_position, &buffer_snapshot)
21122                    .is_le(),
21123                "replace_range should start before or at cursor position"
21124            );
21125
21126            let should_replace = match intent {
21127                CompletionIntent::CompleteWithInsert => false,
21128                CompletionIntent::CompleteWithReplace => true,
21129                CompletionIntent::Complete | CompletionIntent::Compose => {
21130                    let insert_mode =
21131                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21132                            .completions
21133                            .lsp_insert_mode;
21134                    match insert_mode {
21135                        LspInsertMode::Insert => false,
21136                        LspInsertMode::Replace => true,
21137                        LspInsertMode::ReplaceSubsequence => {
21138                            let mut text_to_replace = buffer.chars_for_range(
21139                                buffer.anchor_before(replace_range.start)
21140                                    ..buffer.anchor_after(replace_range.end),
21141                            );
21142                            let mut current_needle = text_to_replace.next();
21143                            for haystack_ch in completion.label.text.chars() {
21144                                if let Some(needle_ch) = current_needle {
21145                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
21146                                        current_needle = text_to_replace.next();
21147                                    }
21148                                }
21149                            }
21150                            current_needle.is_none()
21151                        }
21152                        LspInsertMode::ReplaceSuffix => {
21153                            if replace_range
21154                                .end
21155                                .cmp(&cursor_position, &buffer_snapshot)
21156                                .is_gt()
21157                            {
21158                                let range_after_cursor = *cursor_position..replace_range.end;
21159                                let text_after_cursor = buffer
21160                                    .text_for_range(
21161                                        buffer.anchor_before(range_after_cursor.start)
21162                                            ..buffer.anchor_after(range_after_cursor.end),
21163                                    )
21164                                    .collect::<String>()
21165                                    .to_ascii_lowercase();
21166                                completion
21167                                    .label
21168                                    .text
21169                                    .to_ascii_lowercase()
21170                                    .ends_with(&text_after_cursor)
21171                            } else {
21172                                true
21173                            }
21174                        }
21175                    }
21176                }
21177            };
21178
21179            if should_replace {
21180                replace_range.clone()
21181            } else {
21182                insert_range.clone()
21183            }
21184        } else {
21185            replace_range.clone()
21186        }
21187    };
21188
21189    if range_to_replace
21190        .end
21191        .cmp(&cursor_position, &buffer_snapshot)
21192        .is_lt()
21193    {
21194        range_to_replace.end = *cursor_position;
21195    }
21196
21197    CompletionEdit {
21198        new_text,
21199        replace_range: range_to_replace.to_offset(&buffer),
21200        snippet,
21201    }
21202}
21203
21204struct CompletionEdit {
21205    new_text: String,
21206    replace_range: Range<usize>,
21207    snippet: Option<Snippet>,
21208}
21209
21210fn insert_extra_newline_brackets(
21211    buffer: &MultiBufferSnapshot,
21212    range: Range<usize>,
21213    language: &language::LanguageScope,
21214) -> bool {
21215    let leading_whitespace_len = buffer
21216        .reversed_chars_at(range.start)
21217        .take_while(|c| c.is_whitespace() && *c != '\n')
21218        .map(|c| c.len_utf8())
21219        .sum::<usize>();
21220    let trailing_whitespace_len = buffer
21221        .chars_at(range.end)
21222        .take_while(|c| c.is_whitespace() && *c != '\n')
21223        .map(|c| c.len_utf8())
21224        .sum::<usize>();
21225    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21226
21227    language.brackets().any(|(pair, enabled)| {
21228        let pair_start = pair.start.trim_end();
21229        let pair_end = pair.end.trim_start();
21230
21231        enabled
21232            && pair.newline
21233            && buffer.contains_str_at(range.end, pair_end)
21234            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21235    })
21236}
21237
21238fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21239    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21240        [(buffer, range, _)] => (*buffer, range.clone()),
21241        _ => return false,
21242    };
21243    let pair = {
21244        let mut result: Option<BracketMatch> = None;
21245
21246        for pair in buffer
21247            .all_bracket_ranges(range.clone())
21248            .filter(move |pair| {
21249                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21250            })
21251        {
21252            let len = pair.close_range.end - pair.open_range.start;
21253
21254            if let Some(existing) = &result {
21255                let existing_len = existing.close_range.end - existing.open_range.start;
21256                if len > existing_len {
21257                    continue;
21258                }
21259            }
21260
21261            result = Some(pair);
21262        }
21263
21264        result
21265    };
21266    let Some(pair) = pair else {
21267        return false;
21268    };
21269    pair.newline_only
21270        && buffer
21271            .chars_for_range(pair.open_range.end..range.start)
21272            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21273            .all(|c| c.is_whitespace() && c != '\n')
21274}
21275
21276fn update_uncommitted_diff_for_buffer(
21277    editor: Entity<Editor>,
21278    project: &Entity<Project>,
21279    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21280    buffer: Entity<MultiBuffer>,
21281    cx: &mut App,
21282) -> Task<()> {
21283    let mut tasks = Vec::new();
21284    project.update(cx, |project, cx| {
21285        for buffer in buffers {
21286            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21287                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21288            }
21289        }
21290    });
21291    cx.spawn(async move |cx| {
21292        let diffs = future::join_all(tasks).await;
21293        if editor
21294            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21295            .unwrap_or(false)
21296        {
21297            return;
21298        }
21299
21300        buffer
21301            .update(cx, |buffer, cx| {
21302                for diff in diffs.into_iter().flatten() {
21303                    buffer.add_diff(diff, cx);
21304                }
21305            })
21306            .ok();
21307    })
21308}
21309
21310fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21311    let tab_size = tab_size.get() as usize;
21312    let mut width = offset;
21313
21314    for ch in text.chars() {
21315        width += if ch == '\t' {
21316            tab_size - (width % tab_size)
21317        } else {
21318            1
21319        };
21320    }
21321
21322    width - offset
21323}
21324
21325#[cfg(test)]
21326mod tests {
21327    use super::*;
21328
21329    #[test]
21330    fn test_string_size_with_expanded_tabs() {
21331        let nz = |val| NonZeroU32::new(val).unwrap();
21332        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21333        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21334        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21335        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21336        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21337        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21338        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21339        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21340    }
21341}
21342
21343/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21344struct WordBreakingTokenizer<'a> {
21345    input: &'a str,
21346}
21347
21348impl<'a> WordBreakingTokenizer<'a> {
21349    fn new(input: &'a str) -> Self {
21350        Self { input }
21351    }
21352}
21353
21354fn is_char_ideographic(ch: char) -> bool {
21355    use unicode_script::Script::*;
21356    use unicode_script::UnicodeScript;
21357    matches!(ch.script(), Han | Tangut | Yi)
21358}
21359
21360fn is_grapheme_ideographic(text: &str) -> bool {
21361    text.chars().any(is_char_ideographic)
21362}
21363
21364fn is_grapheme_whitespace(text: &str) -> bool {
21365    text.chars().any(|x| x.is_whitespace())
21366}
21367
21368fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21369    text.chars().next().map_or(false, |ch| {
21370        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
21371    })
21372}
21373
21374#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21375enum WordBreakToken<'a> {
21376    Word { token: &'a str, grapheme_len: usize },
21377    InlineWhitespace { token: &'a str, grapheme_len: usize },
21378    Newline,
21379}
21380
21381impl<'a> Iterator for WordBreakingTokenizer<'a> {
21382    /// Yields a span, the count of graphemes in the token, and whether it was
21383    /// whitespace. Note that it also breaks at word boundaries.
21384    type Item = WordBreakToken<'a>;
21385
21386    fn next(&mut self) -> Option<Self::Item> {
21387        use unicode_segmentation::UnicodeSegmentation;
21388        if self.input.is_empty() {
21389            return None;
21390        }
21391
21392        let mut iter = self.input.graphemes(true).peekable();
21393        let mut offset = 0;
21394        let mut grapheme_len = 0;
21395        if let Some(first_grapheme) = iter.next() {
21396            let is_newline = first_grapheme == "\n";
21397            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21398            offset += first_grapheme.len();
21399            grapheme_len += 1;
21400            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21401                if let Some(grapheme) = iter.peek().copied() {
21402                    if should_stay_with_preceding_ideograph(grapheme) {
21403                        offset += grapheme.len();
21404                        grapheme_len += 1;
21405                    }
21406                }
21407            } else {
21408                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21409                let mut next_word_bound = words.peek().copied();
21410                if next_word_bound.map_or(false, |(i, _)| i == 0) {
21411                    next_word_bound = words.next();
21412                }
21413                while let Some(grapheme) = iter.peek().copied() {
21414                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
21415                        break;
21416                    };
21417                    if is_grapheme_whitespace(grapheme) != is_whitespace
21418                        || (grapheme == "\n") != is_newline
21419                    {
21420                        break;
21421                    };
21422                    offset += grapheme.len();
21423                    grapheme_len += 1;
21424                    iter.next();
21425                }
21426            }
21427            let token = &self.input[..offset];
21428            self.input = &self.input[offset..];
21429            if token == "\n" {
21430                Some(WordBreakToken::Newline)
21431            } else if is_whitespace {
21432                Some(WordBreakToken::InlineWhitespace {
21433                    token,
21434                    grapheme_len,
21435                })
21436            } else {
21437                Some(WordBreakToken::Word {
21438                    token,
21439                    grapheme_len,
21440                })
21441            }
21442        } else {
21443            None
21444        }
21445    }
21446}
21447
21448#[test]
21449fn test_word_breaking_tokenizer() {
21450    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21451        ("", &[]),
21452        ("  ", &[whitespace("  ", 2)]),
21453        ("Ʒ", &[word("Ʒ", 1)]),
21454        ("Ǽ", &[word("Ǽ", 1)]),
21455        ("", &[word("", 1)]),
21456        ("⋑⋑", &[word("⋑⋑", 2)]),
21457        (
21458            "原理,进而",
21459            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21460        ),
21461        (
21462            "hello world",
21463            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21464        ),
21465        (
21466            "hello, world",
21467            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21468        ),
21469        (
21470            "  hello world",
21471            &[
21472                whitespace("  ", 2),
21473                word("hello", 5),
21474                whitespace(" ", 1),
21475                word("world", 5),
21476            ],
21477        ),
21478        (
21479            "这是什么 \n 钢笔",
21480            &[
21481                word("", 1),
21482                word("", 1),
21483                word("", 1),
21484                word("", 1),
21485                whitespace(" ", 1),
21486                newline(),
21487                whitespace(" ", 1),
21488                word("", 1),
21489                word("", 1),
21490            ],
21491        ),
21492        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21493    ];
21494
21495    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21496        WordBreakToken::Word {
21497            token,
21498            grapheme_len,
21499        }
21500    }
21501
21502    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21503        WordBreakToken::InlineWhitespace {
21504            token,
21505            grapheme_len,
21506        }
21507    }
21508
21509    fn newline() -> WordBreakToken<'static> {
21510        WordBreakToken::Newline
21511    }
21512
21513    for (input, result) in tests {
21514        assert_eq!(
21515            WordBreakingTokenizer::new(input)
21516                .collect::<Vec<_>>()
21517                .as_slice(),
21518            *result,
21519        );
21520    }
21521}
21522
21523fn wrap_with_prefix(
21524    first_line_prefix: String,
21525    subsequent_lines_prefix: String,
21526    unwrapped_text: String,
21527    wrap_column: usize,
21528    tab_size: NonZeroU32,
21529    preserve_existing_whitespace: bool,
21530) -> String {
21531    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21532    let subsequent_lines_prefix_len =
21533        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21534    let mut wrapped_text = String::new();
21535    let mut current_line = first_line_prefix.clone();
21536    let mut is_first_line = true;
21537
21538    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21539    let mut current_line_len = first_line_prefix_len;
21540    let mut in_whitespace = false;
21541    for token in tokenizer {
21542        let have_preceding_whitespace = in_whitespace;
21543        match token {
21544            WordBreakToken::Word {
21545                token,
21546                grapheme_len,
21547            } => {
21548                in_whitespace = false;
21549                let current_prefix_len = if is_first_line {
21550                    first_line_prefix_len
21551                } else {
21552                    subsequent_lines_prefix_len
21553                };
21554                if current_line_len + grapheme_len > wrap_column
21555                    && current_line_len != current_prefix_len
21556                {
21557                    wrapped_text.push_str(current_line.trim_end());
21558                    wrapped_text.push('\n');
21559                    is_first_line = false;
21560                    current_line = subsequent_lines_prefix.clone();
21561                    current_line_len = subsequent_lines_prefix_len;
21562                }
21563                current_line.push_str(token);
21564                current_line_len += grapheme_len;
21565            }
21566            WordBreakToken::InlineWhitespace {
21567                mut token,
21568                mut grapheme_len,
21569            } => {
21570                in_whitespace = true;
21571                if have_preceding_whitespace && !preserve_existing_whitespace {
21572                    continue;
21573                }
21574                if !preserve_existing_whitespace {
21575                    token = " ";
21576                    grapheme_len = 1;
21577                }
21578                let current_prefix_len = if is_first_line {
21579                    first_line_prefix_len
21580                } else {
21581                    subsequent_lines_prefix_len
21582                };
21583                if current_line_len + grapheme_len > wrap_column {
21584                    wrapped_text.push_str(current_line.trim_end());
21585                    wrapped_text.push('\n');
21586                    is_first_line = false;
21587                    current_line = subsequent_lines_prefix.clone();
21588                    current_line_len = subsequent_lines_prefix_len;
21589                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21590                    current_line.push_str(token);
21591                    current_line_len += grapheme_len;
21592                }
21593            }
21594            WordBreakToken::Newline => {
21595                in_whitespace = true;
21596                let current_prefix_len = if is_first_line {
21597                    first_line_prefix_len
21598                } else {
21599                    subsequent_lines_prefix_len
21600                };
21601                if preserve_existing_whitespace {
21602                    wrapped_text.push_str(current_line.trim_end());
21603                    wrapped_text.push('\n');
21604                    is_first_line = false;
21605                    current_line = subsequent_lines_prefix.clone();
21606                    current_line_len = subsequent_lines_prefix_len;
21607                } else if have_preceding_whitespace {
21608                    continue;
21609                } else if current_line_len + 1 > wrap_column
21610                    && current_line_len != current_prefix_len
21611                {
21612                    wrapped_text.push_str(current_line.trim_end());
21613                    wrapped_text.push('\n');
21614                    is_first_line = false;
21615                    current_line = subsequent_lines_prefix.clone();
21616                    current_line_len = subsequent_lines_prefix_len;
21617                } else if current_line_len != current_prefix_len {
21618                    current_line.push(' ');
21619                    current_line_len += 1;
21620                }
21621            }
21622        }
21623    }
21624
21625    if !current_line.is_empty() {
21626        wrapped_text.push_str(&current_line);
21627    }
21628    wrapped_text
21629}
21630
21631#[test]
21632fn test_wrap_with_prefix() {
21633    assert_eq!(
21634        wrap_with_prefix(
21635            "# ".to_string(),
21636            "# ".to_string(),
21637            "abcdefg".to_string(),
21638            4,
21639            NonZeroU32::new(4).unwrap(),
21640            false,
21641        ),
21642        "# abcdefg"
21643    );
21644    assert_eq!(
21645        wrap_with_prefix(
21646            "".to_string(),
21647            "".to_string(),
21648            "\thello world".to_string(),
21649            8,
21650            NonZeroU32::new(4).unwrap(),
21651            false,
21652        ),
21653        "hello\nworld"
21654    );
21655    assert_eq!(
21656        wrap_with_prefix(
21657            "// ".to_string(),
21658            "// ".to_string(),
21659            "xx \nyy zz aa bb cc".to_string(),
21660            12,
21661            NonZeroU32::new(4).unwrap(),
21662            false,
21663        ),
21664        "// xx yy zz\n// aa bb cc"
21665    );
21666    assert_eq!(
21667        wrap_with_prefix(
21668            String::new(),
21669            String::new(),
21670            "这是什么 \n 钢笔".to_string(),
21671            3,
21672            NonZeroU32::new(4).unwrap(),
21673            false,
21674        ),
21675        "这是什\n么 钢\n"
21676    );
21677}
21678
21679pub trait CollaborationHub {
21680    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21681    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21682    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21683}
21684
21685impl CollaborationHub for Entity<Project> {
21686    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21687        self.read(cx).collaborators()
21688    }
21689
21690    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21691        self.read(cx).user_store().read(cx).participant_indices()
21692    }
21693
21694    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21695        let this = self.read(cx);
21696        let user_ids = this.collaborators().values().map(|c| c.user_id);
21697        this.user_store().read(cx).participant_names(user_ids, cx)
21698    }
21699}
21700
21701pub trait SemanticsProvider {
21702    fn hover(
21703        &self,
21704        buffer: &Entity<Buffer>,
21705        position: text::Anchor,
21706        cx: &mut App,
21707    ) -> Option<Task<Vec<project::Hover>>>;
21708
21709    fn inline_values(
21710        &self,
21711        buffer_handle: Entity<Buffer>,
21712        range: Range<text::Anchor>,
21713        cx: &mut App,
21714    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21715
21716    fn inlay_hints(
21717        &self,
21718        buffer_handle: Entity<Buffer>,
21719        range: Range<text::Anchor>,
21720        cx: &mut App,
21721    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21722
21723    fn resolve_inlay_hint(
21724        &self,
21725        hint: InlayHint,
21726        buffer_handle: Entity<Buffer>,
21727        server_id: LanguageServerId,
21728        cx: &mut App,
21729    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21730
21731    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21732
21733    fn document_highlights(
21734        &self,
21735        buffer: &Entity<Buffer>,
21736        position: text::Anchor,
21737        cx: &mut App,
21738    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21739
21740    fn definitions(
21741        &self,
21742        buffer: &Entity<Buffer>,
21743        position: text::Anchor,
21744        kind: GotoDefinitionKind,
21745        cx: &mut App,
21746    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21747
21748    fn range_for_rename(
21749        &self,
21750        buffer: &Entity<Buffer>,
21751        position: text::Anchor,
21752        cx: &mut App,
21753    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21754
21755    fn perform_rename(
21756        &self,
21757        buffer: &Entity<Buffer>,
21758        position: text::Anchor,
21759        new_name: String,
21760        cx: &mut App,
21761    ) -> Option<Task<Result<ProjectTransaction>>>;
21762}
21763
21764pub trait CompletionProvider {
21765    fn completions(
21766        &self,
21767        excerpt_id: ExcerptId,
21768        buffer: &Entity<Buffer>,
21769        buffer_position: text::Anchor,
21770        trigger: CompletionContext,
21771        window: &mut Window,
21772        cx: &mut Context<Editor>,
21773    ) -> Task<Result<Vec<CompletionResponse>>>;
21774
21775    fn resolve_completions(
21776        &self,
21777        _buffer: Entity<Buffer>,
21778        _completion_indices: Vec<usize>,
21779        _completions: Rc<RefCell<Box<[Completion]>>>,
21780        _cx: &mut Context<Editor>,
21781    ) -> Task<Result<bool>> {
21782        Task::ready(Ok(false))
21783    }
21784
21785    fn apply_additional_edits_for_completion(
21786        &self,
21787        _buffer: Entity<Buffer>,
21788        _completions: Rc<RefCell<Box<[Completion]>>>,
21789        _completion_index: usize,
21790        _push_to_history: bool,
21791        _cx: &mut Context<Editor>,
21792    ) -> Task<Result<Option<language::Transaction>>> {
21793        Task::ready(Ok(None))
21794    }
21795
21796    fn is_completion_trigger(
21797        &self,
21798        buffer: &Entity<Buffer>,
21799        position: language::Anchor,
21800        text: &str,
21801        trigger_in_words: bool,
21802        menu_is_open: bool,
21803        cx: &mut Context<Editor>,
21804    ) -> bool;
21805
21806    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21807
21808    fn sort_completions(&self) -> bool {
21809        true
21810    }
21811
21812    fn filter_completions(&self) -> bool {
21813        true
21814    }
21815}
21816
21817pub trait CodeActionProvider {
21818    fn id(&self) -> Arc<str>;
21819
21820    fn code_actions(
21821        &self,
21822        buffer: &Entity<Buffer>,
21823        range: Range<text::Anchor>,
21824        window: &mut Window,
21825        cx: &mut App,
21826    ) -> Task<Result<Vec<CodeAction>>>;
21827
21828    fn apply_code_action(
21829        &self,
21830        buffer_handle: Entity<Buffer>,
21831        action: CodeAction,
21832        excerpt_id: ExcerptId,
21833        push_to_history: bool,
21834        window: &mut Window,
21835        cx: &mut App,
21836    ) -> Task<Result<ProjectTransaction>>;
21837}
21838
21839impl CodeActionProvider for Entity<Project> {
21840    fn id(&self) -> Arc<str> {
21841        "project".into()
21842    }
21843
21844    fn code_actions(
21845        &self,
21846        buffer: &Entity<Buffer>,
21847        range: Range<text::Anchor>,
21848        _window: &mut Window,
21849        cx: &mut App,
21850    ) -> Task<Result<Vec<CodeAction>>> {
21851        self.update(cx, |project, cx| {
21852            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
21853            let code_actions = project.code_actions(buffer, range, None, cx);
21854            cx.background_spawn(async move {
21855                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
21856                Ok(code_lens_actions
21857                    .context("code lens fetch")?
21858                    .into_iter()
21859                    .chain(code_actions.context("code action fetch")?)
21860                    .collect())
21861            })
21862        })
21863    }
21864
21865    fn apply_code_action(
21866        &self,
21867        buffer_handle: Entity<Buffer>,
21868        action: CodeAction,
21869        _excerpt_id: ExcerptId,
21870        push_to_history: bool,
21871        _window: &mut Window,
21872        cx: &mut App,
21873    ) -> Task<Result<ProjectTransaction>> {
21874        self.update(cx, |project, cx| {
21875            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21876        })
21877    }
21878}
21879
21880fn snippet_completions(
21881    project: &Project,
21882    buffer: &Entity<Buffer>,
21883    buffer_position: text::Anchor,
21884    cx: &mut App,
21885) -> Task<Result<CompletionResponse>> {
21886    let languages = buffer.read(cx).languages_at(buffer_position);
21887    let snippet_store = project.snippets().read(cx);
21888
21889    let scopes: Vec<_> = languages
21890        .iter()
21891        .filter_map(|language| {
21892            let language_name = language.lsp_id();
21893            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21894
21895            if snippets.is_empty() {
21896                None
21897            } else {
21898                Some((language.default_scope(), snippets))
21899            }
21900        })
21901        .collect();
21902
21903    if scopes.is_empty() {
21904        return Task::ready(Ok(CompletionResponse {
21905            completions: vec![],
21906            is_incomplete: false,
21907        }));
21908    }
21909
21910    let snapshot = buffer.read(cx).text_snapshot();
21911    let chars: String = snapshot
21912        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21913        .collect();
21914    let executor = cx.background_executor().clone();
21915
21916    cx.background_spawn(async move {
21917        let mut is_incomplete = false;
21918        let mut completions: Vec<Completion> = Vec::new();
21919        for (scope, snippets) in scopes.into_iter() {
21920            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21921            let mut last_word = chars
21922                .chars()
21923                .take_while(|c| classifier.is_word(*c))
21924                .collect::<String>();
21925            last_word = last_word.chars().rev().collect();
21926
21927            if last_word.is_empty() {
21928                return Ok(CompletionResponse {
21929                    completions: vec![],
21930                    is_incomplete: true,
21931                });
21932            }
21933
21934            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21935            let to_lsp = |point: &text::Anchor| {
21936                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21937                point_to_lsp(end)
21938            };
21939            let lsp_end = to_lsp(&buffer_position);
21940
21941            let candidates = snippets
21942                .iter()
21943                .enumerate()
21944                .flat_map(|(ix, snippet)| {
21945                    snippet
21946                        .prefix
21947                        .iter()
21948                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21949                })
21950                .collect::<Vec<StringMatchCandidate>>();
21951
21952            const MAX_RESULTS: usize = 100;
21953            let mut matches = fuzzy::match_strings(
21954                &candidates,
21955                &last_word,
21956                last_word.chars().any(|c| c.is_uppercase()),
21957                true,
21958                MAX_RESULTS,
21959                &Default::default(),
21960                executor.clone(),
21961            )
21962            .await;
21963
21964            if matches.len() >= MAX_RESULTS {
21965                is_incomplete = true;
21966            }
21967
21968            // Remove all candidates where the query's start does not match the start of any word in the candidate
21969            if let Some(query_start) = last_word.chars().next() {
21970                matches.retain(|string_match| {
21971                    split_words(&string_match.string).any(|word| {
21972                        // Check that the first codepoint of the word as lowercase matches the first
21973                        // codepoint of the query as lowercase
21974                        word.chars()
21975                            .flat_map(|codepoint| codepoint.to_lowercase())
21976                            .zip(query_start.to_lowercase())
21977                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21978                    })
21979                });
21980            }
21981
21982            let matched_strings = matches
21983                .into_iter()
21984                .map(|m| m.string)
21985                .collect::<HashSet<_>>();
21986
21987            completions.extend(snippets.iter().filter_map(|snippet| {
21988                let matching_prefix = snippet
21989                    .prefix
21990                    .iter()
21991                    .find(|prefix| matched_strings.contains(*prefix))?;
21992                let start = as_offset - last_word.len();
21993                let start = snapshot.anchor_before(start);
21994                let range = start..buffer_position;
21995                let lsp_start = to_lsp(&start);
21996                let lsp_range = lsp::Range {
21997                    start: lsp_start,
21998                    end: lsp_end,
21999                };
22000                Some(Completion {
22001                    replace_range: range,
22002                    new_text: snippet.body.clone(),
22003                    source: CompletionSource::Lsp {
22004                        insert_range: None,
22005                        server_id: LanguageServerId(usize::MAX),
22006                        resolved: true,
22007                        lsp_completion: Box::new(lsp::CompletionItem {
22008                            label: snippet.prefix.first().unwrap().clone(),
22009                            kind: Some(CompletionItemKind::SNIPPET),
22010                            label_details: snippet.description.as_ref().map(|description| {
22011                                lsp::CompletionItemLabelDetails {
22012                                    detail: Some(description.clone()),
22013                                    description: None,
22014                                }
22015                            }),
22016                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22017                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22018                                lsp::InsertReplaceEdit {
22019                                    new_text: snippet.body.clone(),
22020                                    insert: lsp_range,
22021                                    replace: lsp_range,
22022                                },
22023                            )),
22024                            filter_text: Some(snippet.body.clone()),
22025                            sort_text: Some(char::MAX.to_string()),
22026                            ..lsp::CompletionItem::default()
22027                        }),
22028                        lsp_defaults: None,
22029                    },
22030                    label: CodeLabel {
22031                        text: matching_prefix.clone(),
22032                        runs: Vec::new(),
22033                        filter_range: 0..matching_prefix.len(),
22034                    },
22035                    icon_path: None,
22036                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22037                        single_line: snippet.name.clone().into(),
22038                        plain_text: snippet
22039                            .description
22040                            .clone()
22041                            .map(|description| description.into()),
22042                    }),
22043                    insert_text_mode: None,
22044                    confirm: None,
22045                })
22046            }))
22047        }
22048
22049        Ok(CompletionResponse {
22050            completions,
22051            is_incomplete,
22052        })
22053    })
22054}
22055
22056impl CompletionProvider for Entity<Project> {
22057    fn completions(
22058        &self,
22059        _excerpt_id: ExcerptId,
22060        buffer: &Entity<Buffer>,
22061        buffer_position: text::Anchor,
22062        options: CompletionContext,
22063        _window: &mut Window,
22064        cx: &mut Context<Editor>,
22065    ) -> Task<Result<Vec<CompletionResponse>>> {
22066        self.update(cx, |project, cx| {
22067            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22068            let project_completions = project.completions(buffer, buffer_position, options, cx);
22069            cx.background_spawn(async move {
22070                let mut responses = project_completions.await?;
22071                let snippets = snippets.await?;
22072                if !snippets.completions.is_empty() {
22073                    responses.push(snippets);
22074                }
22075                Ok(responses)
22076            })
22077        })
22078    }
22079
22080    fn resolve_completions(
22081        &self,
22082        buffer: Entity<Buffer>,
22083        completion_indices: Vec<usize>,
22084        completions: Rc<RefCell<Box<[Completion]>>>,
22085        cx: &mut Context<Editor>,
22086    ) -> Task<Result<bool>> {
22087        self.update(cx, |project, cx| {
22088            project.lsp_store().update(cx, |lsp_store, cx| {
22089                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22090            })
22091        })
22092    }
22093
22094    fn apply_additional_edits_for_completion(
22095        &self,
22096        buffer: Entity<Buffer>,
22097        completions: Rc<RefCell<Box<[Completion]>>>,
22098        completion_index: usize,
22099        push_to_history: bool,
22100        cx: &mut Context<Editor>,
22101    ) -> Task<Result<Option<language::Transaction>>> {
22102        self.update(cx, |project, cx| {
22103            project.lsp_store().update(cx, |lsp_store, cx| {
22104                lsp_store.apply_additional_edits_for_completion(
22105                    buffer,
22106                    completions,
22107                    completion_index,
22108                    push_to_history,
22109                    cx,
22110                )
22111            })
22112        })
22113    }
22114
22115    fn is_completion_trigger(
22116        &self,
22117        buffer: &Entity<Buffer>,
22118        position: language::Anchor,
22119        text: &str,
22120        trigger_in_words: bool,
22121        menu_is_open: bool,
22122        cx: &mut Context<Editor>,
22123    ) -> bool {
22124        let mut chars = text.chars();
22125        let char = if let Some(char) = chars.next() {
22126            char
22127        } else {
22128            return false;
22129        };
22130        if chars.next().is_some() {
22131            return false;
22132        }
22133
22134        let buffer = buffer.read(cx);
22135        let snapshot = buffer.snapshot();
22136        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22137            return false;
22138        }
22139        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22140        if trigger_in_words && classifier.is_word(char) {
22141            return true;
22142        }
22143
22144        buffer.completion_triggers().contains(text)
22145    }
22146}
22147
22148impl SemanticsProvider for Entity<Project> {
22149    fn hover(
22150        &self,
22151        buffer: &Entity<Buffer>,
22152        position: text::Anchor,
22153        cx: &mut App,
22154    ) -> Option<Task<Vec<project::Hover>>> {
22155        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22156    }
22157
22158    fn document_highlights(
22159        &self,
22160        buffer: &Entity<Buffer>,
22161        position: text::Anchor,
22162        cx: &mut App,
22163    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22164        Some(self.update(cx, |project, cx| {
22165            project.document_highlights(buffer, position, cx)
22166        }))
22167    }
22168
22169    fn definitions(
22170        &self,
22171        buffer: &Entity<Buffer>,
22172        position: text::Anchor,
22173        kind: GotoDefinitionKind,
22174        cx: &mut App,
22175    ) -> Option<Task<Result<Vec<LocationLink>>>> {
22176        Some(self.update(cx, |project, cx| match kind {
22177            GotoDefinitionKind::Symbol => project.definitions(&buffer, position, cx),
22178            GotoDefinitionKind::Declaration => project.declarations(&buffer, position, cx),
22179            GotoDefinitionKind::Type => project.type_definitions(&buffer, position, cx),
22180            GotoDefinitionKind::Implementation => project.implementations(&buffer, position, cx),
22181        }))
22182    }
22183
22184    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22185        // TODO: make this work for remote projects
22186        self.update(cx, |project, cx| {
22187            if project
22188                .active_debug_session(cx)
22189                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22190            {
22191                return true;
22192            }
22193
22194            buffer.update(cx, |buffer, cx| {
22195                project.any_language_server_supports_inlay_hints(buffer, cx)
22196            })
22197        })
22198    }
22199
22200    fn inline_values(
22201        &self,
22202        buffer_handle: Entity<Buffer>,
22203        range: Range<text::Anchor>,
22204        cx: &mut App,
22205    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22206        self.update(cx, |project, cx| {
22207            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22208
22209            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22210        })
22211    }
22212
22213    fn inlay_hints(
22214        &self,
22215        buffer_handle: Entity<Buffer>,
22216        range: Range<text::Anchor>,
22217        cx: &mut App,
22218    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22219        Some(self.update(cx, |project, cx| {
22220            project.inlay_hints(buffer_handle, range, cx)
22221        }))
22222    }
22223
22224    fn resolve_inlay_hint(
22225        &self,
22226        hint: InlayHint,
22227        buffer_handle: Entity<Buffer>,
22228        server_id: LanguageServerId,
22229        cx: &mut App,
22230    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22231        Some(self.update(cx, |project, cx| {
22232            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22233        }))
22234    }
22235
22236    fn range_for_rename(
22237        &self,
22238        buffer: &Entity<Buffer>,
22239        position: text::Anchor,
22240        cx: &mut App,
22241    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22242        Some(self.update(cx, |project, cx| {
22243            let buffer = buffer.clone();
22244            let task = project.prepare_rename(buffer.clone(), position, cx);
22245            cx.spawn(async move |_, cx| {
22246                Ok(match task.await? {
22247                    PrepareRenameResponse::Success(range) => Some(range),
22248                    PrepareRenameResponse::InvalidPosition => None,
22249                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22250                        // Fallback on using TreeSitter info to determine identifier range
22251                        buffer.read_with(cx, |buffer, _| {
22252                            let snapshot = buffer.snapshot();
22253                            let (range, kind) = snapshot.surrounding_word(position, false);
22254                            if kind != Some(CharKind::Word) {
22255                                return None;
22256                            }
22257                            Some(
22258                                snapshot.anchor_before(range.start)
22259                                    ..snapshot.anchor_after(range.end),
22260                            )
22261                        })?
22262                    }
22263                })
22264            })
22265        }))
22266    }
22267
22268    fn perform_rename(
22269        &self,
22270        buffer: &Entity<Buffer>,
22271        position: text::Anchor,
22272        new_name: String,
22273        cx: &mut App,
22274    ) -> Option<Task<Result<ProjectTransaction>>> {
22275        Some(self.update(cx, |project, cx| {
22276            project.perform_rename(buffer.clone(), position, new_name, cx)
22277        }))
22278    }
22279}
22280
22281fn inlay_hint_settings(
22282    location: Anchor,
22283    snapshot: &MultiBufferSnapshot,
22284    cx: &mut Context<Editor>,
22285) -> InlayHintSettings {
22286    let file = snapshot.file_at(location);
22287    let language = snapshot.language_at(location).map(|l| l.name());
22288    language_settings(language, file, cx).inlay_hints
22289}
22290
22291fn consume_contiguous_rows(
22292    contiguous_row_selections: &mut Vec<Selection<Point>>,
22293    selection: &Selection<Point>,
22294    display_map: &DisplaySnapshot,
22295    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22296) -> (MultiBufferRow, MultiBufferRow) {
22297    contiguous_row_selections.push(selection.clone());
22298    let start_row = starting_row(selection, display_map);
22299    let mut end_row = ending_row(selection, display_map);
22300
22301    while let Some(next_selection) = selections.peek() {
22302        if next_selection.start.row <= end_row.0 {
22303            end_row = ending_row(next_selection, display_map);
22304            contiguous_row_selections.push(selections.next().unwrap().clone());
22305        } else {
22306            break;
22307        }
22308    }
22309    (start_row, end_row)
22310}
22311
22312fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22313    if selection.start.column > 0 {
22314        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22315    } else {
22316        MultiBufferRow(selection.start.row)
22317    }
22318}
22319
22320fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22321    if next_selection.end.column > 0 || next_selection.is_empty() {
22322        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22323    } else {
22324        MultiBufferRow(next_selection.end.row)
22325    }
22326}
22327
22328impl EditorSnapshot {
22329    pub fn remote_selections_in_range<'a>(
22330        &'a self,
22331        range: &'a Range<Anchor>,
22332        collaboration_hub: &dyn CollaborationHub,
22333        cx: &'a App,
22334    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22335        let participant_names = collaboration_hub.user_names(cx);
22336        let participant_indices = collaboration_hub.user_participant_indices(cx);
22337        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22338        let collaborators_by_replica_id = collaborators_by_peer_id
22339            .values()
22340            .map(|collaborator| (collaborator.replica_id, collaborator))
22341            .collect::<HashMap<_, _>>();
22342        self.buffer_snapshot
22343            .selections_in_range(range, false)
22344            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22345                if replica_id == AGENT_REPLICA_ID {
22346                    Some(RemoteSelection {
22347                        replica_id,
22348                        selection,
22349                        cursor_shape,
22350                        line_mode,
22351                        collaborator_id: CollaboratorId::Agent,
22352                        user_name: Some("Agent".into()),
22353                        color: cx.theme().players().agent(),
22354                    })
22355                } else {
22356                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22357                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22358                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22359                    Some(RemoteSelection {
22360                        replica_id,
22361                        selection,
22362                        cursor_shape,
22363                        line_mode,
22364                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22365                        user_name,
22366                        color: if let Some(index) = participant_index {
22367                            cx.theme().players().color_for_participant(index.0)
22368                        } else {
22369                            cx.theme().players().absent()
22370                        },
22371                    })
22372                }
22373            })
22374    }
22375
22376    pub fn hunks_for_ranges(
22377        &self,
22378        ranges: impl IntoIterator<Item = Range<Point>>,
22379    ) -> Vec<MultiBufferDiffHunk> {
22380        let mut hunks = Vec::new();
22381        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22382            HashMap::default();
22383        for query_range in ranges {
22384            let query_rows =
22385                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22386            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22387                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22388            ) {
22389                // Include deleted hunks that are adjacent to the query range, because
22390                // otherwise they would be missed.
22391                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22392                if hunk.status().is_deleted() {
22393                    intersects_range |= hunk.row_range.start == query_rows.end;
22394                    intersects_range |= hunk.row_range.end == query_rows.start;
22395                }
22396                if intersects_range {
22397                    if !processed_buffer_rows
22398                        .entry(hunk.buffer_id)
22399                        .or_default()
22400                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22401                    {
22402                        continue;
22403                    }
22404                    hunks.push(hunk);
22405                }
22406            }
22407        }
22408
22409        hunks
22410    }
22411
22412    fn display_diff_hunks_for_rows<'a>(
22413        &'a self,
22414        display_rows: Range<DisplayRow>,
22415        folded_buffers: &'a HashSet<BufferId>,
22416    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22417        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22418        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22419
22420        self.buffer_snapshot
22421            .diff_hunks_in_range(buffer_start..buffer_end)
22422            .filter_map(|hunk| {
22423                if folded_buffers.contains(&hunk.buffer_id) {
22424                    return None;
22425                }
22426
22427                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22428                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22429
22430                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22431                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22432
22433                let display_hunk = if hunk_display_start.column() != 0 {
22434                    DisplayDiffHunk::Folded {
22435                        display_row: hunk_display_start.row(),
22436                    }
22437                } else {
22438                    let mut end_row = hunk_display_end.row();
22439                    if hunk_display_end.column() > 0 {
22440                        end_row.0 += 1;
22441                    }
22442                    let is_created_file = hunk.is_created_file();
22443                    DisplayDiffHunk::Unfolded {
22444                        status: hunk.status(),
22445                        diff_base_byte_range: hunk.diff_base_byte_range,
22446                        display_row_range: hunk_display_start.row()..end_row,
22447                        multi_buffer_range: Anchor::range_in_buffer(
22448                            hunk.excerpt_id,
22449                            hunk.buffer_id,
22450                            hunk.buffer_range,
22451                        ),
22452                        is_created_file,
22453                    }
22454                };
22455
22456                Some(display_hunk)
22457            })
22458    }
22459
22460    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22461        self.display_snapshot.buffer_snapshot.language_at(position)
22462    }
22463
22464    pub fn is_focused(&self) -> bool {
22465        self.is_focused
22466    }
22467
22468    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22469        self.placeholder_text.as_ref()
22470    }
22471
22472    pub fn scroll_position(&self) -> gpui::Point<f32> {
22473        self.scroll_anchor.scroll_position(&self.display_snapshot)
22474    }
22475
22476    fn gutter_dimensions(
22477        &self,
22478        font_id: FontId,
22479        font_size: Pixels,
22480        max_line_number_width: Pixels,
22481        cx: &App,
22482    ) -> Option<GutterDimensions> {
22483        if !self.show_gutter {
22484            return None;
22485        }
22486
22487        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22488        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22489
22490        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22491            matches!(
22492                ProjectSettings::get_global(cx).git.git_gutter,
22493                Some(GitGutterSetting::TrackedFiles)
22494            )
22495        });
22496        let gutter_settings = EditorSettings::get_global(cx).gutter;
22497        let show_line_numbers = self
22498            .show_line_numbers
22499            .unwrap_or(gutter_settings.line_numbers);
22500        let line_gutter_width = if show_line_numbers {
22501            // Avoid flicker-like gutter resizes when the line number gains another digit by
22502            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22503            let min_width_for_number_on_gutter =
22504                ch_advance * gutter_settings.min_line_number_digits as f32;
22505            max_line_number_width.max(min_width_for_number_on_gutter)
22506        } else {
22507            0.0.into()
22508        };
22509
22510        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22511        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22512
22513        let git_blame_entries_width =
22514            self.git_blame_gutter_max_author_length
22515                .map(|max_author_length| {
22516                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22517                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22518
22519                    /// The number of characters to dedicate to gaps and margins.
22520                    const SPACING_WIDTH: usize = 4;
22521
22522                    let max_char_count = max_author_length.min(renderer.max_author_length())
22523                        + ::git::SHORT_SHA_LENGTH
22524                        + MAX_RELATIVE_TIMESTAMP.len()
22525                        + SPACING_WIDTH;
22526
22527                    ch_advance * max_char_count
22528                });
22529
22530        let is_singleton = self.buffer_snapshot.is_singleton();
22531
22532        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22533        left_padding += if !is_singleton {
22534            ch_width * 4.0
22535        } else if show_runnables || show_breakpoints {
22536            ch_width * 3.0
22537        } else if show_git_gutter && show_line_numbers {
22538            ch_width * 2.0
22539        } else if show_git_gutter || show_line_numbers {
22540            ch_width
22541        } else {
22542            px(0.)
22543        };
22544
22545        let shows_folds = is_singleton && gutter_settings.folds;
22546
22547        let right_padding = if shows_folds && show_line_numbers {
22548            ch_width * 4.0
22549        } else if shows_folds || (!is_singleton && show_line_numbers) {
22550            ch_width * 3.0
22551        } else if show_line_numbers {
22552            ch_width
22553        } else {
22554            px(0.)
22555        };
22556
22557        Some(GutterDimensions {
22558            left_padding,
22559            right_padding,
22560            width: line_gutter_width + left_padding + right_padding,
22561            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22562            git_blame_entries_width,
22563        })
22564    }
22565
22566    pub fn render_crease_toggle(
22567        &self,
22568        buffer_row: MultiBufferRow,
22569        row_contains_cursor: bool,
22570        editor: Entity<Editor>,
22571        window: &mut Window,
22572        cx: &mut App,
22573    ) -> Option<AnyElement> {
22574        let folded = self.is_line_folded(buffer_row);
22575        let mut is_foldable = false;
22576
22577        if let Some(crease) = self
22578            .crease_snapshot
22579            .query_row(buffer_row, &self.buffer_snapshot)
22580        {
22581            is_foldable = true;
22582            match crease {
22583                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22584                    if let Some(render_toggle) = render_toggle {
22585                        let toggle_callback =
22586                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22587                                if folded {
22588                                    editor.update(cx, |editor, cx| {
22589                                        editor.fold_at(buffer_row, window, cx)
22590                                    });
22591                                } else {
22592                                    editor.update(cx, |editor, cx| {
22593                                        editor.unfold_at(buffer_row, window, cx)
22594                                    });
22595                                }
22596                            });
22597                        return Some((render_toggle)(
22598                            buffer_row,
22599                            folded,
22600                            toggle_callback,
22601                            window,
22602                            cx,
22603                        ));
22604                    }
22605                }
22606            }
22607        }
22608
22609        is_foldable |= self.starts_indent(buffer_row);
22610
22611        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22612            Some(
22613                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22614                    .toggle_state(folded)
22615                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22616                        if folded {
22617                            this.unfold_at(buffer_row, window, cx);
22618                        } else {
22619                            this.fold_at(buffer_row, window, cx);
22620                        }
22621                    }))
22622                    .into_any_element(),
22623            )
22624        } else {
22625            None
22626        }
22627    }
22628
22629    pub fn render_crease_trailer(
22630        &self,
22631        buffer_row: MultiBufferRow,
22632        window: &mut Window,
22633        cx: &mut App,
22634    ) -> Option<AnyElement> {
22635        let folded = self.is_line_folded(buffer_row);
22636        if let Crease::Inline { render_trailer, .. } = self
22637            .crease_snapshot
22638            .query_row(buffer_row, &self.buffer_snapshot)?
22639        {
22640            let render_trailer = render_trailer.as_ref()?;
22641            Some(render_trailer(buffer_row, folded, window, cx))
22642        } else {
22643            None
22644        }
22645    }
22646}
22647
22648impl Deref for EditorSnapshot {
22649    type Target = DisplaySnapshot;
22650
22651    fn deref(&self) -> &Self::Target {
22652        &self.display_snapshot
22653    }
22654}
22655
22656#[derive(Clone, Debug, PartialEq, Eq)]
22657pub enum EditorEvent {
22658    InputIgnored {
22659        text: Arc<str>,
22660    },
22661    InputHandled {
22662        utf16_range_to_replace: Option<Range<isize>>,
22663        text: Arc<str>,
22664    },
22665    ExcerptsAdded {
22666        buffer: Entity<Buffer>,
22667        predecessor: ExcerptId,
22668        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22669    },
22670    ExcerptsRemoved {
22671        ids: Vec<ExcerptId>,
22672        removed_buffer_ids: Vec<BufferId>,
22673    },
22674    BufferFoldToggled {
22675        ids: Vec<ExcerptId>,
22676        folded: bool,
22677    },
22678    ExcerptsEdited {
22679        ids: Vec<ExcerptId>,
22680    },
22681    ExcerptsExpanded {
22682        ids: Vec<ExcerptId>,
22683    },
22684    BufferEdited,
22685    Edited {
22686        transaction_id: clock::Lamport,
22687    },
22688    Reparsed(BufferId),
22689    Focused,
22690    FocusedIn,
22691    Blurred,
22692    DirtyChanged,
22693    Saved,
22694    TitleChanged,
22695    DiffBaseChanged,
22696    SelectionsChanged {
22697        local: bool,
22698    },
22699    ScrollPositionChanged {
22700        local: bool,
22701        autoscroll: bool,
22702    },
22703    Closed,
22704    TransactionUndone {
22705        transaction_id: clock::Lamport,
22706    },
22707    TransactionBegun {
22708        transaction_id: clock::Lamport,
22709    },
22710    Reloaded,
22711    CursorShapeChanged,
22712    PushedToNavHistory {
22713        anchor: Anchor,
22714        is_deactivate: bool,
22715    },
22716}
22717
22718impl EventEmitter<EditorEvent> for Editor {}
22719
22720impl Focusable for Editor {
22721    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22722        self.focus_handle.clone()
22723    }
22724}
22725
22726impl Render for Editor {
22727    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22728        let settings = ThemeSettings::get_global(cx);
22729
22730        let mut text_style = match self.mode {
22731            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22732                color: cx.theme().colors().editor_foreground,
22733                font_family: settings.ui_font.family.clone(),
22734                font_features: settings.ui_font.features.clone(),
22735                font_fallbacks: settings.ui_font.fallbacks.clone(),
22736                font_size: rems(0.875).into(),
22737                font_weight: settings.ui_font.weight,
22738                line_height: relative(settings.buffer_line_height.value()),
22739                ..Default::default()
22740            },
22741            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22742                color: cx.theme().colors().editor_foreground,
22743                font_family: settings.buffer_font.family.clone(),
22744                font_features: settings.buffer_font.features.clone(),
22745                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22746                font_size: settings.buffer_font_size(cx).into(),
22747                font_weight: settings.buffer_font.weight,
22748                line_height: relative(settings.buffer_line_height.value()),
22749                ..Default::default()
22750            },
22751        };
22752        if let Some(text_style_refinement) = &self.text_style_refinement {
22753            text_style.refine(text_style_refinement)
22754        }
22755
22756        let background = match self.mode {
22757            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22758            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22759            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22760            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22761        };
22762
22763        EditorElement::new(
22764            &cx.entity(),
22765            EditorStyle {
22766                background,
22767                border: cx.theme().colors().border,
22768                local_player: cx.theme().players().local(),
22769                text: text_style,
22770                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22771                syntax: cx.theme().syntax().clone(),
22772                status: cx.theme().status().clone(),
22773                inlay_hints_style: make_inlay_hints_style(cx),
22774                inline_completion_styles: make_suggestion_styles(cx),
22775                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22776                show_underlines: self.diagnostics_enabled(),
22777            },
22778        )
22779    }
22780}
22781
22782impl EntityInputHandler for Editor {
22783    fn text_for_range(
22784        &mut self,
22785        range_utf16: Range<usize>,
22786        adjusted_range: &mut Option<Range<usize>>,
22787        _: &mut Window,
22788        cx: &mut Context<Self>,
22789    ) -> Option<String> {
22790        let snapshot = self.buffer.read(cx).read(cx);
22791        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22792        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22793        if (start.0..end.0) != range_utf16 {
22794            adjusted_range.replace(start.0..end.0);
22795        }
22796        Some(snapshot.text_for_range(start..end).collect())
22797    }
22798
22799    fn selected_text_range(
22800        &mut self,
22801        ignore_disabled_input: bool,
22802        _: &mut Window,
22803        cx: &mut Context<Self>,
22804    ) -> Option<UTF16Selection> {
22805        // Prevent the IME menu from appearing when holding down an alphabetic key
22806        // while input is disabled.
22807        if !ignore_disabled_input && !self.input_enabled {
22808            return None;
22809        }
22810
22811        let selection = self.selections.newest::<OffsetUtf16>(cx);
22812        let range = selection.range();
22813
22814        Some(UTF16Selection {
22815            range: range.start.0..range.end.0,
22816            reversed: selection.reversed,
22817        })
22818    }
22819
22820    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22821        let snapshot = self.buffer.read(cx).read(cx);
22822        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22823        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22824    }
22825
22826    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22827        self.clear_highlights::<InputComposition>(cx);
22828        self.ime_transaction.take();
22829    }
22830
22831    fn replace_text_in_range(
22832        &mut self,
22833        range_utf16: Option<Range<usize>>,
22834        text: &str,
22835        window: &mut Window,
22836        cx: &mut Context<Self>,
22837    ) {
22838        if !self.input_enabled {
22839            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22840            return;
22841        }
22842
22843        self.transact(window, cx, |this, window, cx| {
22844            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22845                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22846                Some(this.selection_replacement_ranges(range_utf16, cx))
22847            } else {
22848                this.marked_text_ranges(cx)
22849            };
22850
22851            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22852                let newest_selection_id = this.selections.newest_anchor().id;
22853                this.selections
22854                    .all::<OffsetUtf16>(cx)
22855                    .iter()
22856                    .zip(ranges_to_replace.iter())
22857                    .find_map(|(selection, range)| {
22858                        if selection.id == newest_selection_id {
22859                            Some(
22860                                (range.start.0 as isize - selection.head().0 as isize)
22861                                    ..(range.end.0 as isize - selection.head().0 as isize),
22862                            )
22863                        } else {
22864                            None
22865                        }
22866                    })
22867            });
22868
22869            cx.emit(EditorEvent::InputHandled {
22870                utf16_range_to_replace: range_to_replace,
22871                text: text.into(),
22872            });
22873
22874            if let Some(new_selected_ranges) = new_selected_ranges {
22875                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22876                    selections.select_ranges(new_selected_ranges)
22877                });
22878                this.backspace(&Default::default(), window, cx);
22879            }
22880
22881            this.handle_input(text, window, cx);
22882        });
22883
22884        if let Some(transaction) = self.ime_transaction {
22885            self.buffer.update(cx, |buffer, cx| {
22886                buffer.group_until_transaction(transaction, cx);
22887            });
22888        }
22889
22890        self.unmark_text(window, cx);
22891    }
22892
22893    fn replace_and_mark_text_in_range(
22894        &mut self,
22895        range_utf16: Option<Range<usize>>,
22896        text: &str,
22897        new_selected_range_utf16: Option<Range<usize>>,
22898        window: &mut Window,
22899        cx: &mut Context<Self>,
22900    ) {
22901        if !self.input_enabled {
22902            return;
22903        }
22904
22905        let transaction = self.transact(window, cx, |this, window, cx| {
22906            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22907                let snapshot = this.buffer.read(cx).read(cx);
22908                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22909                    for marked_range in &mut marked_ranges {
22910                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22911                        marked_range.start.0 += relative_range_utf16.start;
22912                        marked_range.start =
22913                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22914                        marked_range.end =
22915                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22916                    }
22917                }
22918                Some(marked_ranges)
22919            } else if let Some(range_utf16) = range_utf16 {
22920                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22921                Some(this.selection_replacement_ranges(range_utf16, cx))
22922            } else {
22923                None
22924            };
22925
22926            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22927                let newest_selection_id = this.selections.newest_anchor().id;
22928                this.selections
22929                    .all::<OffsetUtf16>(cx)
22930                    .iter()
22931                    .zip(ranges_to_replace.iter())
22932                    .find_map(|(selection, range)| {
22933                        if selection.id == newest_selection_id {
22934                            Some(
22935                                (range.start.0 as isize - selection.head().0 as isize)
22936                                    ..(range.end.0 as isize - selection.head().0 as isize),
22937                            )
22938                        } else {
22939                            None
22940                        }
22941                    })
22942            });
22943
22944            cx.emit(EditorEvent::InputHandled {
22945                utf16_range_to_replace: range_to_replace,
22946                text: text.into(),
22947            });
22948
22949            if let Some(ranges) = ranges_to_replace {
22950                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22951                    s.select_ranges(ranges)
22952                });
22953            }
22954
22955            let marked_ranges = {
22956                let snapshot = this.buffer.read(cx).read(cx);
22957                this.selections
22958                    .disjoint_anchors()
22959                    .iter()
22960                    .map(|selection| {
22961                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22962                    })
22963                    .collect::<Vec<_>>()
22964            };
22965
22966            if text.is_empty() {
22967                this.unmark_text(window, cx);
22968            } else {
22969                this.highlight_text::<InputComposition>(
22970                    marked_ranges.clone(),
22971                    HighlightStyle {
22972                        underline: Some(UnderlineStyle {
22973                            thickness: px(1.),
22974                            color: None,
22975                            wavy: false,
22976                        }),
22977                        ..Default::default()
22978                    },
22979                    cx,
22980                );
22981            }
22982
22983            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22984            let use_autoclose = this.use_autoclose;
22985            let use_auto_surround = this.use_auto_surround;
22986            this.set_use_autoclose(false);
22987            this.set_use_auto_surround(false);
22988            this.handle_input(text, window, cx);
22989            this.set_use_autoclose(use_autoclose);
22990            this.set_use_auto_surround(use_auto_surround);
22991
22992            if let Some(new_selected_range) = new_selected_range_utf16 {
22993                let snapshot = this.buffer.read(cx).read(cx);
22994                let new_selected_ranges = marked_ranges
22995                    .into_iter()
22996                    .map(|marked_range| {
22997                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22998                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22999                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23000                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23001                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23002                    })
23003                    .collect::<Vec<_>>();
23004
23005                drop(snapshot);
23006                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23007                    selections.select_ranges(new_selected_ranges)
23008                });
23009            }
23010        });
23011
23012        self.ime_transaction = self.ime_transaction.or(transaction);
23013        if let Some(transaction) = self.ime_transaction {
23014            self.buffer.update(cx, |buffer, cx| {
23015                buffer.group_until_transaction(transaction, cx);
23016            });
23017        }
23018
23019        if self.text_highlights::<InputComposition>(cx).is_none() {
23020            self.ime_transaction.take();
23021        }
23022    }
23023
23024    fn bounds_for_range(
23025        &mut self,
23026        range_utf16: Range<usize>,
23027        element_bounds: gpui::Bounds<Pixels>,
23028        window: &mut Window,
23029        cx: &mut Context<Self>,
23030    ) -> Option<gpui::Bounds<Pixels>> {
23031        let text_layout_details = self.text_layout_details(window);
23032        let CharacterDimensions {
23033            em_width,
23034            em_advance,
23035            line_height,
23036        } = self.character_dimensions(window);
23037
23038        let snapshot = self.snapshot(window, cx);
23039        let scroll_position = snapshot.scroll_position();
23040        let scroll_left = scroll_position.x * em_advance;
23041
23042        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23043        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23044            + self.gutter_dimensions.full_width();
23045        let y = line_height * (start.row().as_f32() - scroll_position.y);
23046
23047        Some(Bounds {
23048            origin: element_bounds.origin + point(x, y),
23049            size: size(em_width, line_height),
23050        })
23051    }
23052
23053    fn character_index_for_point(
23054        &mut self,
23055        point: gpui::Point<Pixels>,
23056        _window: &mut Window,
23057        _cx: &mut Context<Self>,
23058    ) -> Option<usize> {
23059        let position_map = self.last_position_map.as_ref()?;
23060        if !position_map.text_hitbox.contains(&point) {
23061            return None;
23062        }
23063        let display_point = position_map.point_for_position(point).previous_valid;
23064        let anchor = position_map
23065            .snapshot
23066            .display_point_to_anchor(display_point, Bias::Left);
23067        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23068        Some(utf16_offset.0)
23069    }
23070}
23071
23072trait SelectionExt {
23073    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23074    fn spanned_rows(
23075        &self,
23076        include_end_if_at_line_start: bool,
23077        map: &DisplaySnapshot,
23078    ) -> Range<MultiBufferRow>;
23079}
23080
23081impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23082    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23083        let start = self
23084            .start
23085            .to_point(&map.buffer_snapshot)
23086            .to_display_point(map);
23087        let end = self
23088            .end
23089            .to_point(&map.buffer_snapshot)
23090            .to_display_point(map);
23091        if self.reversed {
23092            end..start
23093        } else {
23094            start..end
23095        }
23096    }
23097
23098    fn spanned_rows(
23099        &self,
23100        include_end_if_at_line_start: bool,
23101        map: &DisplaySnapshot,
23102    ) -> Range<MultiBufferRow> {
23103        let start = self.start.to_point(&map.buffer_snapshot);
23104        let mut end = self.end.to_point(&map.buffer_snapshot);
23105        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23106            end.row -= 1;
23107        }
23108
23109        let buffer_start = map.prev_line_boundary(start).0;
23110        let buffer_end = map.next_line_boundary(end).0;
23111        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23112    }
23113}
23114
23115impl<T: InvalidationRegion> InvalidationStack<T> {
23116    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23117    where
23118        S: Clone + ToOffset,
23119    {
23120        while let Some(region) = self.last() {
23121            let all_selections_inside_invalidation_ranges =
23122                if selections.len() == region.ranges().len() {
23123                    selections
23124                        .iter()
23125                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23126                        .all(|(selection, invalidation_range)| {
23127                            let head = selection.head().to_offset(buffer);
23128                            invalidation_range.start <= head && invalidation_range.end >= head
23129                        })
23130                } else {
23131                    false
23132                };
23133
23134            if all_selections_inside_invalidation_ranges {
23135                break;
23136            } else {
23137                self.pop();
23138            }
23139        }
23140    }
23141}
23142
23143impl<T> Default for InvalidationStack<T> {
23144    fn default() -> Self {
23145        Self(Default::default())
23146    }
23147}
23148
23149impl<T> Deref for InvalidationStack<T> {
23150    type Target = Vec<T>;
23151
23152    fn deref(&self) -> &Self::Target {
23153        &self.0
23154    }
23155}
23156
23157impl<T> DerefMut for InvalidationStack<T> {
23158    fn deref_mut(&mut self) -> &mut Self::Target {
23159        &mut self.0
23160    }
23161}
23162
23163impl InvalidationRegion for SnippetState {
23164    fn ranges(&self) -> &[Range<Anchor>] {
23165        &self.ranges[self.active_index]
23166    }
23167}
23168
23169fn inline_completion_edit_text(
23170    current_snapshot: &BufferSnapshot,
23171    edits: &[(Range<Anchor>, String)],
23172    edit_preview: &EditPreview,
23173    include_deletions: bool,
23174    cx: &App,
23175) -> HighlightedText {
23176    let edits = edits
23177        .iter()
23178        .map(|(anchor, text)| {
23179            (
23180                anchor.start.text_anchor..anchor.end.text_anchor,
23181                text.clone(),
23182            )
23183        })
23184        .collect::<Vec<_>>();
23185
23186    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23187}
23188
23189pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23190    match severity {
23191        lsp::DiagnosticSeverity::ERROR => colors.error,
23192        lsp::DiagnosticSeverity::WARNING => colors.warning,
23193        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23194        lsp::DiagnosticSeverity::HINT => colors.info,
23195        _ => colors.ignored,
23196    }
23197}
23198
23199pub fn styled_runs_for_code_label<'a>(
23200    label: &'a CodeLabel,
23201    syntax_theme: &'a theme::SyntaxTheme,
23202) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23203    let fade_out = HighlightStyle {
23204        fade_out: Some(0.35),
23205        ..Default::default()
23206    };
23207
23208    let mut prev_end = label.filter_range.end;
23209    label
23210        .runs
23211        .iter()
23212        .enumerate()
23213        .flat_map(move |(ix, (range, highlight_id))| {
23214            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23215                style
23216            } else {
23217                return Default::default();
23218            };
23219            let mut muted_style = style;
23220            muted_style.highlight(fade_out);
23221
23222            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23223            if range.start >= label.filter_range.end {
23224                if range.start > prev_end {
23225                    runs.push((prev_end..range.start, fade_out));
23226                }
23227                runs.push((range.clone(), muted_style));
23228            } else if range.end <= label.filter_range.end {
23229                runs.push((range.clone(), style));
23230            } else {
23231                runs.push((range.start..label.filter_range.end, style));
23232                runs.push((label.filter_range.end..range.end, muted_style));
23233            }
23234            prev_end = cmp::max(prev_end, range.end);
23235
23236            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23237                runs.push((prev_end..label.text.len(), fade_out));
23238            }
23239
23240            runs
23241        })
23242}
23243
23244pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23245    let mut prev_index = 0;
23246    let mut prev_codepoint: Option<char> = None;
23247    text.char_indices()
23248        .chain([(text.len(), '\0')])
23249        .filter_map(move |(index, codepoint)| {
23250            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23251            let is_boundary = index == text.len()
23252                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23253                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23254            if is_boundary {
23255                let chunk = &text[prev_index..index];
23256                prev_index = index;
23257                Some(chunk)
23258            } else {
23259                None
23260            }
23261        })
23262}
23263
23264pub trait RangeToAnchorExt: Sized {
23265    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23266
23267    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23268        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23269        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23270    }
23271}
23272
23273impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23274    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23275        let start_offset = self.start.to_offset(snapshot);
23276        let end_offset = self.end.to_offset(snapshot);
23277        if start_offset == end_offset {
23278            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23279        } else {
23280            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23281        }
23282    }
23283}
23284
23285pub trait RowExt {
23286    fn as_f32(&self) -> f32;
23287
23288    fn next_row(&self) -> Self;
23289
23290    fn previous_row(&self) -> Self;
23291
23292    fn minus(&self, other: Self) -> u32;
23293}
23294
23295impl RowExt for DisplayRow {
23296    fn as_f32(&self) -> f32 {
23297        self.0 as f32
23298    }
23299
23300    fn next_row(&self) -> Self {
23301        Self(self.0 + 1)
23302    }
23303
23304    fn previous_row(&self) -> Self {
23305        Self(self.0.saturating_sub(1))
23306    }
23307
23308    fn minus(&self, other: Self) -> u32 {
23309        self.0 - other.0
23310    }
23311}
23312
23313impl RowExt for MultiBufferRow {
23314    fn as_f32(&self) -> f32 {
23315        self.0 as f32
23316    }
23317
23318    fn next_row(&self) -> Self {
23319        Self(self.0 + 1)
23320    }
23321
23322    fn previous_row(&self) -> Self {
23323        Self(self.0.saturating_sub(1))
23324    }
23325
23326    fn minus(&self, other: Self) -> u32 {
23327        self.0 - other.0
23328    }
23329}
23330
23331trait RowRangeExt {
23332    type Row;
23333
23334    fn len(&self) -> usize;
23335
23336    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23337}
23338
23339impl RowRangeExt for Range<MultiBufferRow> {
23340    type Row = MultiBufferRow;
23341
23342    fn len(&self) -> usize {
23343        (self.end.0 - self.start.0) as usize
23344    }
23345
23346    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23347        (self.start.0..self.end.0).map(MultiBufferRow)
23348    }
23349}
23350
23351impl RowRangeExt for Range<DisplayRow> {
23352    type Row = DisplayRow;
23353
23354    fn len(&self) -> usize {
23355        (self.end.0 - self.start.0) as usize
23356    }
23357
23358    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23359        (self.start.0..self.end.0).map(DisplayRow)
23360    }
23361}
23362
23363/// If select range has more than one line, we
23364/// just point the cursor to range.start.
23365fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23366    if range.start.row == range.end.row {
23367        range
23368    } else {
23369        range.start..range.start
23370    }
23371}
23372pub struct KillRing(ClipboardItem);
23373impl Global for KillRing {}
23374
23375const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23376
23377enum BreakpointPromptEditAction {
23378    Log,
23379    Condition,
23380    HitCondition,
23381}
23382
23383struct BreakpointPromptEditor {
23384    pub(crate) prompt: Entity<Editor>,
23385    editor: WeakEntity<Editor>,
23386    breakpoint_anchor: Anchor,
23387    breakpoint: Breakpoint,
23388    edit_action: BreakpointPromptEditAction,
23389    block_ids: HashSet<CustomBlockId>,
23390    editor_margins: Arc<Mutex<EditorMargins>>,
23391    _subscriptions: Vec<Subscription>,
23392}
23393
23394impl BreakpointPromptEditor {
23395    const MAX_LINES: u8 = 4;
23396
23397    fn new(
23398        editor: WeakEntity<Editor>,
23399        breakpoint_anchor: Anchor,
23400        breakpoint: Breakpoint,
23401        edit_action: BreakpointPromptEditAction,
23402        window: &mut Window,
23403        cx: &mut Context<Self>,
23404    ) -> Self {
23405        let base_text = match edit_action {
23406            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23407            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23408            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23409        }
23410        .map(|msg| msg.to_string())
23411        .unwrap_or_default();
23412
23413        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23414        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23415
23416        let prompt = cx.new(|cx| {
23417            let mut prompt = Editor::new(
23418                EditorMode::AutoHeight {
23419                    min_lines: 1,
23420                    max_lines: Some(Self::MAX_LINES as usize),
23421                },
23422                buffer,
23423                None,
23424                window,
23425                cx,
23426            );
23427            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23428            prompt.set_show_cursor_when_unfocused(false, cx);
23429            prompt.set_placeholder_text(
23430                match edit_action {
23431                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23432                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23433                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23434                },
23435                cx,
23436            );
23437
23438            prompt
23439        });
23440
23441        Self {
23442            prompt,
23443            editor,
23444            breakpoint_anchor,
23445            breakpoint,
23446            edit_action,
23447            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23448            block_ids: Default::default(),
23449            _subscriptions: vec![],
23450        }
23451    }
23452
23453    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23454        self.block_ids.extend(block_ids)
23455    }
23456
23457    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23458        if let Some(editor) = self.editor.upgrade() {
23459            let message = self
23460                .prompt
23461                .read(cx)
23462                .buffer
23463                .read(cx)
23464                .as_singleton()
23465                .expect("A multi buffer in breakpoint prompt isn't possible")
23466                .read(cx)
23467                .as_rope()
23468                .to_string();
23469
23470            editor.update(cx, |editor, cx| {
23471                editor.edit_breakpoint_at_anchor(
23472                    self.breakpoint_anchor,
23473                    self.breakpoint.clone(),
23474                    match self.edit_action {
23475                        BreakpointPromptEditAction::Log => {
23476                            BreakpointEditAction::EditLogMessage(message.into())
23477                        }
23478                        BreakpointPromptEditAction::Condition => {
23479                            BreakpointEditAction::EditCondition(message.into())
23480                        }
23481                        BreakpointPromptEditAction::HitCondition => {
23482                            BreakpointEditAction::EditHitCondition(message.into())
23483                        }
23484                    },
23485                    cx,
23486                );
23487
23488                editor.remove_blocks(self.block_ids.clone(), None, cx);
23489                cx.focus_self(window);
23490            });
23491        }
23492    }
23493
23494    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23495        self.editor
23496            .update(cx, |editor, cx| {
23497                editor.remove_blocks(self.block_ids.clone(), None, cx);
23498                window.focus(&editor.focus_handle);
23499            })
23500            .log_err();
23501    }
23502
23503    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23504        let settings = ThemeSettings::get_global(cx);
23505        let text_style = TextStyle {
23506            color: if self.prompt.read(cx).read_only(cx) {
23507                cx.theme().colors().text_disabled
23508            } else {
23509                cx.theme().colors().text
23510            },
23511            font_family: settings.buffer_font.family.clone(),
23512            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23513            font_size: settings.buffer_font_size(cx).into(),
23514            font_weight: settings.buffer_font.weight,
23515            line_height: relative(settings.buffer_line_height.value()),
23516            ..Default::default()
23517        };
23518        EditorElement::new(
23519            &self.prompt,
23520            EditorStyle {
23521                background: cx.theme().colors().editor_background,
23522                local_player: cx.theme().players().local(),
23523                text: text_style,
23524                ..Default::default()
23525            },
23526        )
23527    }
23528}
23529
23530impl Render for BreakpointPromptEditor {
23531    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23532        let editor_margins = *self.editor_margins.lock();
23533        let gutter_dimensions = editor_margins.gutter;
23534        h_flex()
23535            .key_context("Editor")
23536            .bg(cx.theme().colors().editor_background)
23537            .border_y_1()
23538            .border_color(cx.theme().status().info_border)
23539            .size_full()
23540            .py(window.line_height() / 2.5)
23541            .on_action(cx.listener(Self::confirm))
23542            .on_action(cx.listener(Self::cancel))
23543            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23544            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23545    }
23546}
23547
23548impl Focusable for BreakpointPromptEditor {
23549    fn focus_handle(&self, cx: &App) -> FocusHandle {
23550        self.prompt.focus_handle(cx)
23551    }
23552}
23553
23554fn all_edits_insertions_or_deletions(
23555    edits: &Vec<(Range<Anchor>, String)>,
23556    snapshot: &MultiBufferSnapshot,
23557) -> bool {
23558    let mut all_insertions = true;
23559    let mut all_deletions = true;
23560
23561    for (range, new_text) in edits.iter() {
23562        let range_is_empty = range.to_offset(&snapshot).is_empty();
23563        let text_is_empty = new_text.is_empty();
23564
23565        if range_is_empty != text_is_empty {
23566            if range_is_empty {
23567                all_deletions = false;
23568            } else {
23569                all_insertions = false;
23570            }
23571        } else {
23572            return false;
23573        }
23574
23575        if !all_insertions && !all_deletions {
23576            return false;
23577        }
23578    }
23579    all_insertions || all_deletions
23580}
23581
23582struct MissingEditPredictionKeybindingTooltip;
23583
23584impl Render for MissingEditPredictionKeybindingTooltip {
23585    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23586        ui::tooltip_container(window, cx, |container, _, cx| {
23587            container
23588                .flex_shrink_0()
23589                .max_w_80()
23590                .min_h(rems_from_px(124.))
23591                .justify_between()
23592                .child(
23593                    v_flex()
23594                        .flex_1()
23595                        .text_ui_sm(cx)
23596                        .child(Label::new("Conflict with Accept Keybinding"))
23597                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23598                )
23599                .child(
23600                    h_flex()
23601                        .pb_1()
23602                        .gap_1()
23603                        .items_end()
23604                        .w_full()
23605                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23606                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23607                        }))
23608                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23609                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23610                        })),
23611                )
23612        })
23613    }
23614}
23615
23616#[derive(Debug, Clone, Copy, PartialEq)]
23617pub struct LineHighlight {
23618    pub background: Background,
23619    pub border: Option<gpui::Hsla>,
23620    pub include_gutter: bool,
23621    pub type_id: Option<TypeId>,
23622}
23623
23624struct LineManipulationResult {
23625    pub new_text: String,
23626    pub line_count_before: usize,
23627    pub line_count_after: usize,
23628}
23629
23630fn render_diff_hunk_controls(
23631    row: u32,
23632    status: &DiffHunkStatus,
23633    hunk_range: Range<Anchor>,
23634    is_created_file: bool,
23635    line_height: Pixels,
23636    editor: &Entity<Editor>,
23637    _window: &mut Window,
23638    cx: &mut App,
23639) -> AnyElement {
23640    h_flex()
23641        .h(line_height)
23642        .mr_1()
23643        .gap_1()
23644        .px_0p5()
23645        .pb_1()
23646        .border_x_1()
23647        .border_b_1()
23648        .border_color(cx.theme().colors().border_variant)
23649        .rounded_b_lg()
23650        .bg(cx.theme().colors().editor_background)
23651        .gap_1()
23652        .block_mouse_except_scroll()
23653        .shadow_md()
23654        .child(if status.has_secondary_hunk() {
23655            Button::new(("stage", row as u64), "Stage")
23656                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23657                .tooltip({
23658                    let focus_handle = editor.focus_handle(cx);
23659                    move |window, cx| {
23660                        Tooltip::for_action_in(
23661                            "Stage Hunk",
23662                            &::git::ToggleStaged,
23663                            &focus_handle,
23664                            window,
23665                            cx,
23666                        )
23667                    }
23668                })
23669                .on_click({
23670                    let editor = editor.clone();
23671                    move |_event, _window, cx| {
23672                        editor.update(cx, |editor, cx| {
23673                            editor.stage_or_unstage_diff_hunks(
23674                                true,
23675                                vec![hunk_range.start..hunk_range.start],
23676                                cx,
23677                            );
23678                        });
23679                    }
23680                })
23681        } else {
23682            Button::new(("unstage", row as u64), "Unstage")
23683                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23684                .tooltip({
23685                    let focus_handle = editor.focus_handle(cx);
23686                    move |window, cx| {
23687                        Tooltip::for_action_in(
23688                            "Unstage Hunk",
23689                            &::git::ToggleStaged,
23690                            &focus_handle,
23691                            window,
23692                            cx,
23693                        )
23694                    }
23695                })
23696                .on_click({
23697                    let editor = editor.clone();
23698                    move |_event, _window, cx| {
23699                        editor.update(cx, |editor, cx| {
23700                            editor.stage_or_unstage_diff_hunks(
23701                                false,
23702                                vec![hunk_range.start..hunk_range.start],
23703                                cx,
23704                            );
23705                        });
23706                    }
23707                })
23708        })
23709        .child(
23710            Button::new(("restore", row as u64), "Restore")
23711                .tooltip({
23712                    let focus_handle = editor.focus_handle(cx);
23713                    move |window, cx| {
23714                        Tooltip::for_action_in(
23715                            "Restore Hunk",
23716                            &::git::Restore,
23717                            &focus_handle,
23718                            window,
23719                            cx,
23720                        )
23721                    }
23722                })
23723                .on_click({
23724                    let editor = editor.clone();
23725                    move |_event, window, cx| {
23726                        editor.update(cx, |editor, cx| {
23727                            let snapshot = editor.snapshot(window, cx);
23728                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23729                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23730                        });
23731                    }
23732                })
23733                .disabled(is_created_file),
23734        )
23735        .when(
23736            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23737            |el| {
23738                el.child(
23739                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23740                        .shape(IconButtonShape::Square)
23741                        .icon_size(IconSize::Small)
23742                        // .disabled(!has_multiple_hunks)
23743                        .tooltip({
23744                            let focus_handle = editor.focus_handle(cx);
23745                            move |window, cx| {
23746                                Tooltip::for_action_in(
23747                                    "Next Hunk",
23748                                    &GoToHunk,
23749                                    &focus_handle,
23750                                    window,
23751                                    cx,
23752                                )
23753                            }
23754                        })
23755                        .on_click({
23756                            let editor = editor.clone();
23757                            move |_event, window, cx| {
23758                                editor.update(cx, |editor, cx| {
23759                                    let snapshot = editor.snapshot(window, cx);
23760                                    let position =
23761                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23762                                    editor.go_to_hunk_before_or_after_position(
23763                                        &snapshot,
23764                                        position,
23765                                        Direction::Next,
23766                                        window,
23767                                        cx,
23768                                    );
23769                                    editor.expand_selected_diff_hunks(cx);
23770                                });
23771                            }
23772                        }),
23773                )
23774                .child(
23775                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23776                        .shape(IconButtonShape::Square)
23777                        .icon_size(IconSize::Small)
23778                        // .disabled(!has_multiple_hunks)
23779                        .tooltip({
23780                            let focus_handle = editor.focus_handle(cx);
23781                            move |window, cx| {
23782                                Tooltip::for_action_in(
23783                                    "Previous Hunk",
23784                                    &GoToPreviousHunk,
23785                                    &focus_handle,
23786                                    window,
23787                                    cx,
23788                                )
23789                            }
23790                        })
23791                        .on_click({
23792                            let editor = editor.clone();
23793                            move |_event, window, cx| {
23794                                editor.update(cx, |editor, cx| {
23795                                    let snapshot = editor.snapshot(window, cx);
23796                                    let point =
23797                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23798                                    editor.go_to_hunk_before_or_after_position(
23799                                        &snapshot,
23800                                        point,
23801                                        Direction::Prev,
23802                                        window,
23803                                        cx,
23804                                    );
23805                                    editor.expand_selected_diff_hunks(cx);
23806                                });
23807                            }
23808                        }),
23809                )
23810            },
23811        )
23812        .into_any_element()
23813}