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;
   18mod 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_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod proposed_changes_editor;
   37mod rust_analyzer_ext;
   38pub mod scroll;
   39mod selections_collection;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod editor_tests;
   46#[cfg(test)]
   47mod inline_completion_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use actions::{AcceptEditPrediction, OpenExcerpts, OpenExcerptsSplit};
   54use aho_corasick::AhoCorasick;
   55use anyhow::{Context as _, Result, anyhow};
   56use blink_manager::BlinkManager;
   57use buffer_diff::DiffHunkStatus;
   58use client::{Collaborator, ParticipantIndex};
   59use clock::{AGENT_REPLICA_ID, ReplicaId};
   60use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   61use convert_case::{Case, Casing};
   62use display_map::*;
   63pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   64pub use editor_settings::{
   65    CurrentLineHighlight, EditorSettings, HideMouseMode, ScrollBeyondLastLine, SearchSettings,
   66    ShowScrollbar,
   67};
   68use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   69pub use editor_settings_controls::*;
   70use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   71pub use element::{
   72    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   73};
   74use feature_flags::{DebuggerFeatureFlag, FeatureFlagAppExt};
   75use futures::{
   76    FutureExt,
   77    future::{self, Shared, join},
   78};
   79use fuzzy::StringMatchCandidate;
   80
   81use ::git::blame::BlameEntry;
   82use ::git::{Restore, blame::ParsedCommitMessage};
   83use code_context_menus::{
   84    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   85    CompletionsMenu, ContextMenuOrigin,
   86};
   87use git::blame::{GitBlame, GlobalBlameRenderer};
   88use gpui::{
   89    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   90    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   91    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   92    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   93    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   94    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   95    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   96    div, impl_actions, point, prelude::*, pulsating_between, px, relative, size,
   97};
   98use highlight_matching_bracket::refresh_matching_bracket_highlights;
   99use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  100pub use hover_popover::hover_markdown_style;
  101use hover_popover::{HoverState, hide_hover};
  102use indent_guides::ActiveIndentGuidesState;
  103use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  104pub use inline_completion::Direction;
  105use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  106pub use items::MAX_TAB_TITLE_LEN;
  107use itertools::Itertools;
  108use language::{
  109    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  110    CursorShape, DiagnosticEntry, DiffOptions, DocumentationConfig, EditPredictionsMode,
  111    EditPreview, HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point,
  112    Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  113    language_settings::{
  114        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  115        all_language_settings, language_settings,
  116    },
  117    point_from_lsp, text_diff_with_options,
  118};
  119use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  120use linked_editing_ranges::refresh_linked_ranges;
  121use markdown::Markdown;
  122use mouse_context_menu::MouseContextMenu;
  123use persistence::DB;
  124use project::{
  125    ProjectPath,
  126    debugger::{
  127        breakpoint_store::{
  128            BreakpointEditAction, BreakpointState, BreakpointStore, BreakpointStoreEvent,
  129        },
  130        session::{Session, SessionEvent},
  131    },
  132    project_settings::DiagnosticSeverity,
  133};
  134
  135pub use git::blame::BlameRenderer;
  136pub use proposed_changes_editor::{
  137    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  138};
  139use smallvec::smallvec;
  140use std::{cell::OnceCell, iter::Peekable, ops::Not};
  141use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  142
  143pub use lsp::CompletionContext;
  144use lsp::{
  145    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  146    LanguageServerId, LanguageServerName,
  147};
  148
  149use language::BufferSnapshot;
  150pub use lsp_ext::lsp_tasks;
  151use movement::TextLayoutDetails;
  152pub use multi_buffer::{
  153    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  154    RowInfo, ToOffset, ToPoint,
  155};
  156use multi_buffer::{
  157    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  158    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  159};
  160use parking_lot::Mutex;
  161use project::{
  162    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  163    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  164    TaskSourceKind,
  165    debugger::breakpoint_store::Breakpoint,
  166    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  167    project_settings::{GitGutterSetting, ProjectSettings},
  168};
  169use rand::prelude::*;
  170use rpc::{ErrorExt, proto::*};
  171use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  172use selections_collection::{
  173    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  174};
  175use serde::{Deserialize, Serialize};
  176use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  177use smallvec::SmallVec;
  178use snippet::Snippet;
  179use std::sync::Arc;
  180use std::{
  181    any::TypeId,
  182    borrow::Cow,
  183    cell::RefCell,
  184    cmp::{self, Ordering, Reverse},
  185    mem,
  186    num::NonZeroU32,
  187    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  188    path::{Path, PathBuf},
  189    rc::Rc,
  190    time::{Duration, Instant},
  191};
  192pub use sum_tree::Bias;
  193use sum_tree::TreeMap;
  194use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  195use theme::{
  196    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, ThemeColors, ThemeSettings,
  197    observe_buffer_font_size_adjustment,
  198};
  199use ui::{
  200    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  201    IconSize, 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},
  209    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  210    searchable::SearchEvent,
  211};
  212
  213use crate::hover_links::{find_url, find_url_from_range};
  214use crate::signature_help::{SignatureHelpHiddenBy, SignatureHelpState};
  215
  216pub const FILE_HEADER_HEIGHT: u32 = 2;
  217pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  218pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  219const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  220const MAX_LINE_LEN: usize = 1024;
  221const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  222const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  223pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  224#[doc(hidden)]
  225pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  226const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  227
  228pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  229pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  230pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  231
  232pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  233pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  234pub(crate) const MIN_LINE_NUMBER_DIGITS: u32 = 4;
  235pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  236
  237pub type RenderDiffHunkControlsFn = Arc<
  238    dyn Fn(
  239        u32,
  240        &DiffHunkStatus,
  241        Range<Anchor>,
  242        bool,
  243        Pixels,
  244        &Entity<Editor>,
  245        &mut Window,
  246        &mut App,
  247    ) -> AnyElement,
  248>;
  249
  250const COLUMNAR_SELECTION_MODIFIERS: Modifiers = Modifiers {
  251    alt: true,
  252    shift: true,
  253    control: false,
  254    platform: false,
  255    function: false,
  256};
  257
  258struct InlineValueCache {
  259    enabled: bool,
  260    inlays: Vec<InlayId>,
  261    refresh_task: Task<Option<()>>,
  262}
  263
  264impl InlineValueCache {
  265    fn new(enabled: bool) -> Self {
  266        Self {
  267            enabled,
  268            inlays: Vec::new(),
  269            refresh_task: Task::ready(None),
  270        }
  271    }
  272}
  273
  274#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  275pub enum InlayId {
  276    InlineCompletion(usize),
  277    Hint(usize),
  278    DebuggerValue(usize),
  279}
  280
  281impl InlayId {
  282    fn id(&self) -> usize {
  283        match self {
  284            Self::InlineCompletion(id) => *id,
  285            Self::Hint(id) => *id,
  286            Self::DebuggerValue(id) => *id,
  287        }
  288    }
  289}
  290
  291pub enum ActiveDebugLine {}
  292pub enum DebugStackFrameLine {}
  293enum DocumentHighlightRead {}
  294enum DocumentHighlightWrite {}
  295enum InputComposition {}
  296enum SelectedTextHighlight {}
  297
  298pub enum ConflictsOuter {}
  299pub enum ConflictsOurs {}
  300pub enum ConflictsTheirs {}
  301pub enum ConflictsOursMarker {}
  302pub enum ConflictsTheirsMarker {}
  303
  304#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  305pub enum Navigated {
  306    Yes,
  307    No,
  308}
  309
  310impl Navigated {
  311    pub fn from_bool(yes: bool) -> Navigated {
  312        if yes { Navigated::Yes } else { Navigated::No }
  313    }
  314}
  315
  316#[derive(Debug, Clone, PartialEq, Eq)]
  317enum DisplayDiffHunk {
  318    Folded {
  319        display_row: DisplayRow,
  320    },
  321    Unfolded {
  322        is_created_file: bool,
  323        diff_base_byte_range: Range<usize>,
  324        display_row_range: Range<DisplayRow>,
  325        multi_buffer_range: Range<Anchor>,
  326        status: DiffHunkStatus,
  327    },
  328}
  329
  330pub enum HideMouseCursorOrigin {
  331    TypingAction,
  332    MovementAction,
  333}
  334
  335pub fn init_settings(cx: &mut App) {
  336    EditorSettings::register(cx);
  337}
  338
  339pub fn init(cx: &mut App) {
  340    init_settings(cx);
  341
  342    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  343
  344    workspace::register_project_item::<Editor>(cx);
  345    workspace::FollowableViewRegistry::register::<Editor>(cx);
  346    workspace::register_serializable_item::<Editor>(cx);
  347
  348    cx.observe_new(
  349        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  350            workspace.register_action(Editor::new_file);
  351            workspace.register_action(Editor::new_file_vertical);
  352            workspace.register_action(Editor::new_file_horizontal);
  353            workspace.register_action(Editor::cancel_language_server_work);
  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        goal_column: u32,
  450    },
  451    Extend {
  452        position: DisplayPoint,
  453        click_count: usize,
  454    },
  455    Update {
  456        position: DisplayPoint,
  457        goal_column: u32,
  458        scroll_delta: gpui::Point<f32>,
  459    },
  460    End,
  461}
  462
  463#[derive(Clone, Debug)]
  464pub enum SelectMode {
  465    Character,
  466    Word(Range<Anchor>),
  467    Line(Range<Anchor>),
  468    All,
  469}
  470
  471#[derive(Clone, PartialEq, Eq, Debug)]
  472pub enum EditorMode {
  473    SingleLine {
  474        auto_width: bool,
  475    },
  476    AutoHeight {
  477        max_lines: usize,
  478    },
  479    Full {
  480        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  481        scale_ui_elements_with_buffer_font_size: bool,
  482        /// When set to `true`, the editor will render a background for the active line.
  483        show_active_line_background: bool,
  484        /// When set to `true`, the editor's height will be determined by its content.
  485        sized_by_content: bool,
  486    },
  487    Minimap {
  488        parent: WeakEntity<Editor>,
  489    },
  490}
  491
  492impl EditorMode {
  493    pub fn full() -> Self {
  494        Self::Full {
  495            scale_ui_elements_with_buffer_font_size: true,
  496            show_active_line_background: true,
  497            sized_by_content: false,
  498        }
  499    }
  500
  501    pub fn is_full(&self) -> bool {
  502        matches!(self, Self::Full { .. })
  503    }
  504
  505    fn is_minimap(&self) -> bool {
  506        matches!(self, Self::Minimap { .. })
  507    }
  508}
  509
  510#[derive(Copy, Clone, Debug)]
  511pub enum SoftWrap {
  512    /// Prefer not to wrap at all.
  513    ///
  514    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  515    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  516    GitDiff,
  517    /// Prefer a single line generally, unless an overly long line is encountered.
  518    None,
  519    /// Soft wrap lines that exceed the editor width.
  520    EditorWidth,
  521    /// Soft wrap lines at the preferred line length.
  522    Column(u32),
  523    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  524    Bounded(u32),
  525}
  526
  527#[derive(Clone)]
  528pub struct EditorStyle {
  529    pub background: Hsla,
  530    pub local_player: PlayerColor,
  531    pub text: TextStyle,
  532    pub scrollbar_width: Pixels,
  533    pub syntax: Arc<SyntaxTheme>,
  534    pub status: StatusColors,
  535    pub inlay_hints_style: HighlightStyle,
  536    pub inline_completion_styles: InlineCompletionStyles,
  537    pub unnecessary_code_fade: f32,
  538    pub show_underlines: bool,
  539}
  540
  541impl Default for EditorStyle {
  542    fn default() -> Self {
  543        Self {
  544            background: Hsla::default(),
  545            local_player: PlayerColor::default(),
  546            text: TextStyle::default(),
  547            scrollbar_width: Pixels::default(),
  548            syntax: Default::default(),
  549            // HACK: Status colors don't have a real default.
  550            // We should look into removing the status colors from the editor
  551            // style and retrieve them directly from the theme.
  552            status: StatusColors::dark(),
  553            inlay_hints_style: HighlightStyle::default(),
  554            inline_completion_styles: InlineCompletionStyles {
  555                insertion: HighlightStyle::default(),
  556                whitespace: HighlightStyle::default(),
  557            },
  558            unnecessary_code_fade: Default::default(),
  559            show_underlines: true,
  560        }
  561    }
  562}
  563
  564pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  565    let show_background = language_settings::language_settings(None, None, cx)
  566        .inlay_hints
  567        .show_background;
  568
  569    HighlightStyle {
  570        color: Some(cx.theme().status().hint),
  571        background_color: show_background.then(|| cx.theme().status().hint_background),
  572        ..HighlightStyle::default()
  573    }
  574}
  575
  576pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  577    InlineCompletionStyles {
  578        insertion: HighlightStyle {
  579            color: Some(cx.theme().status().predictive),
  580            ..HighlightStyle::default()
  581        },
  582        whitespace: HighlightStyle {
  583            background_color: Some(cx.theme().status().created_background),
  584            ..HighlightStyle::default()
  585        },
  586    }
  587}
  588
  589type CompletionId = usize;
  590
  591pub(crate) enum EditDisplayMode {
  592    TabAccept,
  593    DiffPopover,
  594    Inline,
  595}
  596
  597enum InlineCompletion {
  598    Edit {
  599        edits: Vec<(Range<Anchor>, String)>,
  600        edit_preview: Option<EditPreview>,
  601        display_mode: EditDisplayMode,
  602        snapshot: BufferSnapshot,
  603    },
  604    Move {
  605        target: Anchor,
  606        snapshot: BufferSnapshot,
  607    },
  608}
  609
  610struct InlineCompletionState {
  611    inlay_ids: Vec<InlayId>,
  612    completion: InlineCompletion,
  613    completion_id: Option<SharedString>,
  614    invalidation_range: Range<Anchor>,
  615}
  616
  617enum EditPredictionSettings {
  618    Disabled,
  619    Enabled {
  620        show_in_menu: bool,
  621        preview_requires_modifier: bool,
  622    },
  623}
  624
  625enum InlineCompletionHighlight {}
  626
  627#[derive(Debug, Clone)]
  628struct InlineDiagnostic {
  629    message: SharedString,
  630    group_id: usize,
  631    is_primary: bool,
  632    start: Point,
  633    severity: lsp::DiagnosticSeverity,
  634}
  635
  636pub enum MenuInlineCompletionsPolicy {
  637    Never,
  638    ByProvider,
  639}
  640
  641pub enum EditPredictionPreview {
  642    /// Modifier is not pressed
  643    Inactive { released_too_fast: bool },
  644    /// Modifier pressed
  645    Active {
  646        since: Instant,
  647        previous_scroll_position: Option<ScrollAnchor>,
  648    },
  649}
  650
  651impl EditPredictionPreview {
  652    pub fn released_too_fast(&self) -> bool {
  653        match self {
  654            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  655            EditPredictionPreview::Active { .. } => false,
  656        }
  657    }
  658
  659    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  660        if let EditPredictionPreview::Active {
  661            previous_scroll_position,
  662            ..
  663        } = self
  664        {
  665            *previous_scroll_position = scroll_position;
  666        }
  667    }
  668}
  669
  670pub struct ContextMenuOptions {
  671    pub min_entries_visible: usize,
  672    pub max_entries_visible: usize,
  673    pub placement: Option<ContextMenuPlacement>,
  674}
  675
  676#[derive(Debug, Clone, PartialEq, Eq)]
  677pub enum ContextMenuPlacement {
  678    Above,
  679    Below,
  680}
  681
  682#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  683struct EditorActionId(usize);
  684
  685impl EditorActionId {
  686    pub fn post_inc(&mut self) -> Self {
  687        let answer = self.0;
  688
  689        *self = Self(answer + 1);
  690
  691        Self(answer)
  692    }
  693}
  694
  695// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  696// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  697
  698type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Arc<[Range<Anchor>]>);
  699type GutterHighlight = (fn(&App) -> Hsla, Arc<[Range<Anchor>]>);
  700
  701#[derive(Default)]
  702struct ScrollbarMarkerState {
  703    scrollbar_size: Size<Pixels>,
  704    dirty: bool,
  705    markers: Arc<[PaintQuad]>,
  706    pending_refresh: Option<Task<Result<()>>>,
  707}
  708
  709impl ScrollbarMarkerState {
  710    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  711        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  712    }
  713}
  714
  715#[derive(Clone, Copy, PartialEq, Eq)]
  716pub enum MinimapVisibility {
  717    Disabled,
  718    Enabled(bool),
  719}
  720
  721impl MinimapVisibility {
  722    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  723        if mode.is_full() {
  724            Self::Enabled(EditorSettings::get_global(cx).minimap.minimap_enabled())
  725        } else {
  726            Self::Disabled
  727        }
  728    }
  729
  730    fn disabled(&self) -> bool {
  731        match *self {
  732            Self::Disabled => true,
  733            _ => false,
  734        }
  735    }
  736
  737    fn visible(&self) -> bool {
  738        match *self {
  739            Self::Enabled(visible) => visible,
  740            _ => false,
  741        }
  742    }
  743
  744    fn toggle_visibility(&self) -> Self {
  745        match *self {
  746            Self::Enabled(visible) => Self::Enabled(!visible),
  747            Self::Disabled => Self::Disabled,
  748        }
  749    }
  750}
  751
  752#[derive(Clone, Debug)]
  753struct RunnableTasks {
  754    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  755    offset: multi_buffer::Anchor,
  756    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  757    column: u32,
  758    // Values of all named captures, including those starting with '_'
  759    extra_variables: HashMap<String, String>,
  760    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  761    context_range: Range<BufferOffset>,
  762}
  763
  764impl RunnableTasks {
  765    fn resolve<'a>(
  766        &'a self,
  767        cx: &'a task::TaskContext,
  768    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  769        self.templates.iter().filter_map(|(kind, template)| {
  770            template
  771                .resolve_task(&kind.to_id_base(), cx)
  772                .map(|task| (kind.clone(), task))
  773        })
  774    }
  775}
  776
  777#[derive(Clone)]
  778struct ResolvedTasks {
  779    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  780    position: Anchor,
  781}
  782
  783#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  784struct BufferOffset(usize);
  785
  786// Addons allow storing per-editor state in other crates (e.g. Vim)
  787pub trait Addon: 'static {
  788    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  789
  790    fn render_buffer_header_controls(
  791        &self,
  792        _: &ExcerptInfo,
  793        _: &Window,
  794        _: &App,
  795    ) -> Option<AnyElement> {
  796        None
  797    }
  798
  799    fn to_any(&self) -> &dyn std::any::Any;
  800
  801    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  802        None
  803    }
  804}
  805
  806/// A set of caret positions, registered when the editor was edited.
  807pub struct ChangeList {
  808    changes: Vec<Vec<Anchor>>,
  809    /// Currently "selected" change.
  810    position: Option<usize>,
  811}
  812
  813impl ChangeList {
  814    pub fn new() -> Self {
  815        Self {
  816            changes: Vec::new(),
  817            position: None,
  818        }
  819    }
  820
  821    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  822    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  823    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  824        if self.changes.is_empty() {
  825            return None;
  826        }
  827
  828        let prev = self.position.unwrap_or(self.changes.len());
  829        let next = if direction == Direction::Prev {
  830            prev.saturating_sub(count)
  831        } else {
  832            (prev + count).min(self.changes.len() - 1)
  833        };
  834        self.position = Some(next);
  835        self.changes.get(next).map(|anchors| anchors.as_slice())
  836    }
  837
  838    /// Adds a new change to the list, resetting the change list position.
  839    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  840        self.position.take();
  841        if pop_state {
  842            self.changes.pop();
  843        }
  844        self.changes.push(new_positions.clone());
  845    }
  846
  847    pub fn last(&self) -> Option<&[Anchor]> {
  848        self.changes.last().map(|anchors| anchors.as_slice())
  849    }
  850}
  851
  852#[derive(Clone)]
  853struct InlineBlamePopoverState {
  854    scroll_handle: ScrollHandle,
  855    commit_message: Option<ParsedCommitMessage>,
  856    markdown: Entity<Markdown>,
  857}
  858
  859struct InlineBlamePopover {
  860    position: gpui::Point<Pixels>,
  861    show_task: Option<Task<()>>,
  862    hide_task: Option<Task<()>>,
  863    popover_bounds: Option<Bounds<Pixels>>,
  864    popover_state: InlineBlamePopoverState,
  865}
  866
  867/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  868/// a breakpoint on them.
  869#[derive(Clone, Copy, Debug)]
  870struct PhantomBreakpointIndicator {
  871    display_row: DisplayRow,
  872    /// There's a small debounce between hovering over the line and showing the indicator.
  873    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  874    is_active: bool,
  875    collides_with_existing_breakpoint: bool,
  876}
  877/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  878///
  879/// See the [module level documentation](self) for more information.
  880pub struct Editor {
  881    focus_handle: FocusHandle,
  882    last_focused_descendant: Option<WeakFocusHandle>,
  883    /// The text buffer being edited
  884    buffer: Entity<MultiBuffer>,
  885    /// Map of how text in the buffer should be displayed.
  886    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  887    pub display_map: Entity<DisplayMap>,
  888    pub selections: SelectionsCollection,
  889    pub scroll_manager: ScrollManager,
  890    /// When inline assist editors are linked, they all render cursors because
  891    /// typing enters text into each of them, even the ones that aren't focused.
  892    pub(crate) show_cursor_when_unfocused: bool,
  893    columnar_selection_tail: Option<Anchor>,
  894    add_selections_state: Option<AddSelectionsState>,
  895    select_next_state: Option<SelectNextState>,
  896    select_prev_state: Option<SelectNextState>,
  897    selection_history: SelectionHistory,
  898    autoclose_regions: Vec<AutocloseRegion>,
  899    snippet_stack: InvalidationStack<SnippetState>,
  900    select_syntax_node_history: SelectSyntaxNodeHistory,
  901    ime_transaction: Option<TransactionId>,
  902    pub diagnostics_max_severity: DiagnosticSeverity,
  903    active_diagnostics: ActiveDiagnostic,
  904    show_inline_diagnostics: bool,
  905    inline_diagnostics_update: Task<()>,
  906    inline_diagnostics_enabled: bool,
  907    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  908    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  909    hard_wrap: Option<usize>,
  910
  911    // TODO: make this a access method
  912    pub project: Option<Entity<Project>>,
  913    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  914    completion_provider: Option<Box<dyn CompletionProvider>>,
  915    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  916    blink_manager: Entity<BlinkManager>,
  917    show_cursor_names: bool,
  918    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  919    pub show_local_selections: bool,
  920    mode: EditorMode,
  921    show_breadcrumbs: bool,
  922    show_gutter: bool,
  923    show_scrollbars: bool,
  924    minimap_visibility: MinimapVisibility,
  925    disable_expand_excerpt_buttons: bool,
  926    show_line_numbers: Option<bool>,
  927    use_relative_line_numbers: Option<bool>,
  928    show_git_diff_gutter: Option<bool>,
  929    show_code_actions: Option<bool>,
  930    show_runnables: Option<bool>,
  931    show_breakpoints: Option<bool>,
  932    show_wrap_guides: Option<bool>,
  933    show_indent_guides: Option<bool>,
  934    placeholder_text: Option<Arc<str>>,
  935    highlight_order: usize,
  936    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  937    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
  938    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
  939    scrollbar_marker_state: ScrollbarMarkerState,
  940    active_indent_guides_state: ActiveIndentGuidesState,
  941    nav_history: Option<ItemNavHistory>,
  942    context_menu: RefCell<Option<CodeContextMenu>>,
  943    context_menu_options: Option<ContextMenuOptions>,
  944    mouse_context_menu: Option<MouseContextMenu>,
  945    completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,
  946    inline_blame_popover: Option<InlineBlamePopover>,
  947    signature_help_state: SignatureHelpState,
  948    auto_signature_help: Option<bool>,
  949    find_all_references_task_sources: Vec<Anchor>,
  950    next_completion_id: CompletionId,
  951    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
  952    code_actions_task: Option<Task<Result<()>>>,
  953    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  954    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  955    document_highlights_task: Option<Task<()>>,
  956    linked_editing_range_task: Option<Task<Option<()>>>,
  957    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
  958    pending_rename: Option<RenameState>,
  959    searchable: bool,
  960    cursor_shape: CursorShape,
  961    current_line_highlight: Option<CurrentLineHighlight>,
  962    collapse_matches: bool,
  963    autoindent_mode: Option<AutoindentMode>,
  964    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
  965    input_enabled: bool,
  966    use_modal_editing: bool,
  967    read_only: bool,
  968    leader_id: Option<CollaboratorId>,
  969    remote_id: Option<ViewId>,
  970    pub hover_state: HoverState,
  971    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
  972    gutter_hovered: bool,
  973    hovered_link_state: Option<HoveredLinkState>,
  974    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
  975    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
  976    active_inline_completion: Option<InlineCompletionState>,
  977    /// Used to prevent flickering as the user types while the menu is open
  978    stale_inline_completion_in_menu: Option<InlineCompletionState>,
  979    edit_prediction_settings: EditPredictionSettings,
  980    inline_completions_hidden_for_vim_mode: bool,
  981    show_inline_completions_override: Option<bool>,
  982    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
  983    edit_prediction_preview: EditPredictionPreview,
  984    edit_prediction_indent_conflict: bool,
  985    edit_prediction_requires_modifier_in_indent_conflict: bool,
  986    inlay_hint_cache: InlayHintCache,
  987    next_inlay_id: usize,
  988    _subscriptions: Vec<Subscription>,
  989    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
  990    gutter_dimensions: GutterDimensions,
  991    style: Option<EditorStyle>,
  992    text_style_refinement: Option<TextStyleRefinement>,
  993    next_editor_action_id: EditorActionId,
  994    editor_actions:
  995        Rc<RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&mut Window, &mut Context<Self>)>>>>,
  996    use_autoclose: bool,
  997    use_auto_surround: bool,
  998    auto_replace_emoji_shortcode: bool,
  999    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1000    show_git_blame_gutter: bool,
 1001    show_git_blame_inline: bool,
 1002    show_git_blame_inline_delay_task: Option<Task<()>>,
 1003    git_blame_inline_enabled: bool,
 1004    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1005    serialize_dirty_buffers: bool,
 1006    show_selection_menu: Option<bool>,
 1007    blame: Option<Entity<GitBlame>>,
 1008    blame_subscription: Option<Subscription>,
 1009    custom_context_menu: Option<
 1010        Box<
 1011            dyn 'static
 1012                + Fn(
 1013                    &mut Self,
 1014                    DisplayPoint,
 1015                    &mut Window,
 1016                    &mut Context<Self>,
 1017                ) -> Option<Entity<ui::ContextMenu>>,
 1018        >,
 1019    >,
 1020    last_bounds: Option<Bounds<Pixels>>,
 1021    last_position_map: Option<Rc<PositionMap>>,
 1022    expect_bounds_change: Option<Bounds<Pixels>>,
 1023    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1024    tasks_update_task: Option<Task<()>>,
 1025    breakpoint_store: Option<Entity<BreakpointStore>>,
 1026    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1027    in_project_search: bool,
 1028    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1029    breadcrumb_header: Option<String>,
 1030    focused_block: Option<FocusedBlock>,
 1031    next_scroll_position: NextScrollCursorCenterTopBottom,
 1032    addons: HashMap<TypeId, Box<dyn Addon>>,
 1033    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1034    load_diff_task: Option<Shared<Task<()>>>,
 1035    /// Whether we are temporarily displaying a diff other than git's
 1036    temporary_diff_override: bool,
 1037    selection_mark_mode: bool,
 1038    toggle_fold_multiple_buffers: Task<()>,
 1039    _scroll_cursor_center_top_bottom_task: Task<()>,
 1040    serialize_selections: Task<()>,
 1041    serialize_folds: Task<()>,
 1042    mouse_cursor_hidden: bool,
 1043    minimap: Option<Entity<Self>>,
 1044    hide_mouse_mode: HideMouseMode,
 1045    pub change_list: ChangeList,
 1046    inline_value_cache: InlineValueCache,
 1047}
 1048
 1049#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1050enum NextScrollCursorCenterTopBottom {
 1051    #[default]
 1052    Center,
 1053    Top,
 1054    Bottom,
 1055}
 1056
 1057impl NextScrollCursorCenterTopBottom {
 1058    fn next(&self) -> Self {
 1059        match self {
 1060            Self::Center => Self::Top,
 1061            Self::Top => Self::Bottom,
 1062            Self::Bottom => Self::Center,
 1063        }
 1064    }
 1065}
 1066
 1067#[derive(Clone)]
 1068pub struct EditorSnapshot {
 1069    pub mode: EditorMode,
 1070    show_gutter: bool,
 1071    show_line_numbers: Option<bool>,
 1072    show_git_diff_gutter: Option<bool>,
 1073    show_runnables: Option<bool>,
 1074    show_breakpoints: Option<bool>,
 1075    git_blame_gutter_max_author_length: Option<usize>,
 1076    pub display_snapshot: DisplaySnapshot,
 1077    pub placeholder_text: Option<Arc<str>>,
 1078    is_focused: bool,
 1079    scroll_anchor: ScrollAnchor,
 1080    ongoing_scroll: OngoingScroll,
 1081    current_line_highlight: CurrentLineHighlight,
 1082    gutter_hovered: bool,
 1083}
 1084
 1085#[derive(Default, Debug, Clone, Copy)]
 1086pub struct GutterDimensions {
 1087    pub left_padding: Pixels,
 1088    pub right_padding: Pixels,
 1089    pub width: Pixels,
 1090    pub margin: Pixels,
 1091    pub git_blame_entries_width: Option<Pixels>,
 1092}
 1093
 1094impl GutterDimensions {
 1095    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1096        Self {
 1097            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1098            ..Default::default()
 1099        }
 1100    }
 1101
 1102    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1103        -cx.text_system().descent(font_id, font_size)
 1104    }
 1105    /// The full width of the space taken up by the gutter.
 1106    pub fn full_width(&self) -> Pixels {
 1107        self.margin + self.width
 1108    }
 1109
 1110    /// The width of the space reserved for the fold indicators,
 1111    /// use alongside 'justify_end' and `gutter_width` to
 1112    /// right align content with the line numbers
 1113    pub fn fold_area_width(&self) -> Pixels {
 1114        self.margin + self.right_padding
 1115    }
 1116}
 1117
 1118#[derive(Debug)]
 1119pub struct RemoteSelection {
 1120    pub replica_id: ReplicaId,
 1121    pub selection: Selection<Anchor>,
 1122    pub cursor_shape: CursorShape,
 1123    pub collaborator_id: CollaboratorId,
 1124    pub line_mode: bool,
 1125    pub user_name: Option<SharedString>,
 1126    pub color: PlayerColor,
 1127}
 1128
 1129#[derive(Clone, Debug)]
 1130struct SelectionHistoryEntry {
 1131    selections: Arc<[Selection<Anchor>]>,
 1132    select_next_state: Option<SelectNextState>,
 1133    select_prev_state: Option<SelectNextState>,
 1134    add_selections_state: Option<AddSelectionsState>,
 1135}
 1136
 1137enum SelectionHistoryMode {
 1138    Normal,
 1139    Undoing,
 1140    Redoing,
 1141}
 1142
 1143#[derive(Clone, PartialEq, Eq, Hash)]
 1144struct HoveredCursor {
 1145    replica_id: u16,
 1146    selection_id: usize,
 1147}
 1148
 1149impl Default for SelectionHistoryMode {
 1150    fn default() -> Self {
 1151        Self::Normal
 1152    }
 1153}
 1154
 1155#[derive(Default)]
 1156struct SelectionHistory {
 1157    #[allow(clippy::type_complexity)]
 1158    selections_by_transaction:
 1159        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1160    mode: SelectionHistoryMode,
 1161    undo_stack: VecDeque<SelectionHistoryEntry>,
 1162    redo_stack: VecDeque<SelectionHistoryEntry>,
 1163}
 1164
 1165impl SelectionHistory {
 1166    fn insert_transaction(
 1167        &mut self,
 1168        transaction_id: TransactionId,
 1169        selections: Arc<[Selection<Anchor>]>,
 1170    ) {
 1171        self.selections_by_transaction
 1172            .insert(transaction_id, (selections, None));
 1173    }
 1174
 1175    #[allow(clippy::type_complexity)]
 1176    fn transaction(
 1177        &self,
 1178        transaction_id: TransactionId,
 1179    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1180        self.selections_by_transaction.get(&transaction_id)
 1181    }
 1182
 1183    #[allow(clippy::type_complexity)]
 1184    fn transaction_mut(
 1185        &mut self,
 1186        transaction_id: TransactionId,
 1187    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1188        self.selections_by_transaction.get_mut(&transaction_id)
 1189    }
 1190
 1191    fn push(&mut self, entry: SelectionHistoryEntry) {
 1192        if !entry.selections.is_empty() {
 1193            match self.mode {
 1194                SelectionHistoryMode::Normal => {
 1195                    self.push_undo(entry);
 1196                    self.redo_stack.clear();
 1197                }
 1198                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1199                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1200            }
 1201        }
 1202    }
 1203
 1204    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1205        if self
 1206            .undo_stack
 1207            .back()
 1208            .map_or(true, |e| e.selections != entry.selections)
 1209        {
 1210            self.undo_stack.push_back(entry);
 1211            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1212                self.undo_stack.pop_front();
 1213            }
 1214        }
 1215    }
 1216
 1217    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1218        if self
 1219            .redo_stack
 1220            .back()
 1221            .map_or(true, |e| e.selections != entry.selections)
 1222        {
 1223            self.redo_stack.push_back(entry);
 1224            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1225                self.redo_stack.pop_front();
 1226            }
 1227        }
 1228    }
 1229}
 1230
 1231#[derive(Clone, Copy)]
 1232pub struct RowHighlightOptions {
 1233    pub autoscroll: bool,
 1234    pub include_gutter: bool,
 1235}
 1236
 1237impl Default for RowHighlightOptions {
 1238    fn default() -> Self {
 1239        Self {
 1240            autoscroll: Default::default(),
 1241            include_gutter: true,
 1242        }
 1243    }
 1244}
 1245
 1246struct RowHighlight {
 1247    index: usize,
 1248    range: Range<Anchor>,
 1249    color: Hsla,
 1250    options: RowHighlightOptions,
 1251    type_id: TypeId,
 1252}
 1253
 1254#[derive(Clone, Debug)]
 1255struct AddSelectionsState {
 1256    above: bool,
 1257    stack: Vec<usize>,
 1258}
 1259
 1260#[derive(Clone)]
 1261struct SelectNextState {
 1262    query: AhoCorasick,
 1263    wordwise: bool,
 1264    done: bool,
 1265}
 1266
 1267impl std::fmt::Debug for SelectNextState {
 1268    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1269        f.debug_struct(std::any::type_name::<Self>())
 1270            .field("wordwise", &self.wordwise)
 1271            .field("done", &self.done)
 1272            .finish()
 1273    }
 1274}
 1275
 1276#[derive(Debug)]
 1277struct AutocloseRegion {
 1278    selection_id: usize,
 1279    range: Range<Anchor>,
 1280    pair: BracketPair,
 1281}
 1282
 1283#[derive(Debug)]
 1284struct SnippetState {
 1285    ranges: Vec<Vec<Range<Anchor>>>,
 1286    active_index: usize,
 1287    choices: Vec<Option<Vec<String>>>,
 1288}
 1289
 1290#[doc(hidden)]
 1291pub struct RenameState {
 1292    pub range: Range<Anchor>,
 1293    pub old_name: Arc<str>,
 1294    pub editor: Entity<Editor>,
 1295    block_id: CustomBlockId,
 1296}
 1297
 1298struct InvalidationStack<T>(Vec<T>);
 1299
 1300struct RegisteredInlineCompletionProvider {
 1301    provider: Arc<dyn InlineCompletionProviderHandle>,
 1302    _subscription: Subscription,
 1303}
 1304
 1305#[derive(Debug, PartialEq, Eq)]
 1306pub struct ActiveDiagnosticGroup {
 1307    pub active_range: Range<Anchor>,
 1308    pub active_message: String,
 1309    pub group_id: usize,
 1310    pub blocks: HashSet<CustomBlockId>,
 1311}
 1312
 1313#[derive(Debug, PartialEq, Eq)]
 1314
 1315pub(crate) enum ActiveDiagnostic {
 1316    None,
 1317    All,
 1318    Group(ActiveDiagnosticGroup),
 1319}
 1320
 1321#[derive(Serialize, Deserialize, Clone, Debug)]
 1322pub struct ClipboardSelection {
 1323    /// The number of bytes in this selection.
 1324    pub len: usize,
 1325    /// Whether this was a full-line selection.
 1326    pub is_entire_line: bool,
 1327    /// The indentation of the first line when this content was originally copied.
 1328    pub first_line_indent: u32,
 1329}
 1330
 1331// selections, scroll behavior, was newest selection reversed
 1332type SelectSyntaxNodeHistoryState = (
 1333    Box<[Selection<usize>]>,
 1334    SelectSyntaxNodeScrollBehavior,
 1335    bool,
 1336);
 1337
 1338#[derive(Default)]
 1339struct SelectSyntaxNodeHistory {
 1340    stack: Vec<SelectSyntaxNodeHistoryState>,
 1341    // disable temporarily to allow changing selections without losing the stack
 1342    pub disable_clearing: bool,
 1343}
 1344
 1345impl SelectSyntaxNodeHistory {
 1346    pub fn try_clear(&mut self) {
 1347        if !self.disable_clearing {
 1348            self.stack.clear();
 1349        }
 1350    }
 1351
 1352    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1353        self.stack.push(selection);
 1354    }
 1355
 1356    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1357        self.stack.pop()
 1358    }
 1359}
 1360
 1361enum SelectSyntaxNodeScrollBehavior {
 1362    CursorTop,
 1363    FitSelection,
 1364    CursorBottom,
 1365}
 1366
 1367#[derive(Debug)]
 1368pub(crate) struct NavigationData {
 1369    cursor_anchor: Anchor,
 1370    cursor_position: Point,
 1371    scroll_anchor: ScrollAnchor,
 1372    scroll_top_row: u32,
 1373}
 1374
 1375#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1376pub enum GotoDefinitionKind {
 1377    Symbol,
 1378    Declaration,
 1379    Type,
 1380    Implementation,
 1381}
 1382
 1383#[derive(Debug, Clone)]
 1384enum InlayHintRefreshReason {
 1385    ModifiersChanged(bool),
 1386    Toggle(bool),
 1387    SettingsChange(InlayHintSettings),
 1388    NewLinesShown,
 1389    BufferEdited(HashSet<Arc<Language>>),
 1390    RefreshRequested,
 1391    ExcerptsRemoved(Vec<ExcerptId>),
 1392}
 1393
 1394impl InlayHintRefreshReason {
 1395    fn description(&self) -> &'static str {
 1396        match self {
 1397            Self::ModifiersChanged(_) => "modifiers changed",
 1398            Self::Toggle(_) => "toggle",
 1399            Self::SettingsChange(_) => "settings change",
 1400            Self::NewLinesShown => "new lines shown",
 1401            Self::BufferEdited(_) => "buffer edited",
 1402            Self::RefreshRequested => "refresh requested",
 1403            Self::ExcerptsRemoved(_) => "excerpts removed",
 1404        }
 1405    }
 1406}
 1407
 1408pub enum FormatTarget {
 1409    Buffers,
 1410    Ranges(Vec<Range<MultiBufferPoint>>),
 1411}
 1412
 1413pub(crate) struct FocusedBlock {
 1414    id: BlockId,
 1415    focus_handle: WeakFocusHandle,
 1416}
 1417
 1418#[derive(Clone)]
 1419enum JumpData {
 1420    MultiBufferRow {
 1421        row: MultiBufferRow,
 1422        line_offset_from_top: u32,
 1423    },
 1424    MultiBufferPoint {
 1425        excerpt_id: ExcerptId,
 1426        position: Point,
 1427        anchor: text::Anchor,
 1428        line_offset_from_top: u32,
 1429    },
 1430}
 1431
 1432pub enum MultibufferSelectionMode {
 1433    First,
 1434    All,
 1435}
 1436
 1437#[derive(Clone, Copy, Debug, Default)]
 1438pub struct RewrapOptions {
 1439    pub override_language_settings: bool,
 1440    pub preserve_existing_whitespace: bool,
 1441}
 1442
 1443impl Editor {
 1444    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1445        let buffer = cx.new(|cx| Buffer::local("", cx));
 1446        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1447        Self::new(
 1448            EditorMode::SingleLine { auto_width: false },
 1449            buffer,
 1450            None,
 1451            window,
 1452            cx,
 1453        )
 1454    }
 1455
 1456    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1457        let buffer = cx.new(|cx| Buffer::local("", cx));
 1458        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1459        Self::new(EditorMode::full(), buffer, None, window, cx)
 1460    }
 1461
 1462    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1463        let buffer = cx.new(|cx| Buffer::local("", cx));
 1464        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1465        Self::new(
 1466            EditorMode::SingleLine { auto_width: true },
 1467            buffer,
 1468            None,
 1469            window,
 1470            cx,
 1471        )
 1472    }
 1473
 1474    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1475        let buffer = cx.new(|cx| Buffer::local("", cx));
 1476        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1477        Self::new(
 1478            EditorMode::AutoHeight { max_lines },
 1479            buffer,
 1480            None,
 1481            window,
 1482            cx,
 1483        )
 1484    }
 1485
 1486    pub fn for_buffer(
 1487        buffer: Entity<Buffer>,
 1488        project: Option<Entity<Project>>,
 1489        window: &mut Window,
 1490        cx: &mut Context<Self>,
 1491    ) -> Self {
 1492        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1493        Self::new(EditorMode::full(), buffer, project, window, cx)
 1494    }
 1495
 1496    pub fn for_multibuffer(
 1497        buffer: Entity<MultiBuffer>,
 1498        project: Option<Entity<Project>>,
 1499        window: &mut Window,
 1500        cx: &mut Context<Self>,
 1501    ) -> Self {
 1502        Self::new(EditorMode::full(), buffer, project, window, cx)
 1503    }
 1504
 1505    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1506        let mut clone = Self::new(
 1507            self.mode.clone(),
 1508            self.buffer.clone(),
 1509            self.project.clone(),
 1510            window,
 1511            cx,
 1512        );
 1513        self.display_map.update(cx, |display_map, cx| {
 1514            let snapshot = display_map.snapshot(cx);
 1515            clone.display_map.update(cx, |display_map, cx| {
 1516                display_map.set_state(&snapshot, cx);
 1517            });
 1518        });
 1519        clone.folds_did_change(cx);
 1520        clone.selections.clone_state(&self.selections);
 1521        clone.scroll_manager.clone_state(&self.scroll_manager);
 1522        clone.searchable = self.searchable;
 1523        clone.read_only = self.read_only;
 1524        clone
 1525    }
 1526
 1527    pub fn new(
 1528        mode: EditorMode,
 1529        buffer: Entity<MultiBuffer>,
 1530        project: Option<Entity<Project>>,
 1531        window: &mut Window,
 1532        cx: &mut Context<Self>,
 1533    ) -> Self {
 1534        Editor::new_internal(mode, buffer, project, None, window, cx)
 1535    }
 1536
 1537    fn new_internal(
 1538        mode: EditorMode,
 1539        buffer: Entity<MultiBuffer>,
 1540        project: Option<Entity<Project>>,
 1541        display_map: Option<Entity<DisplayMap>>,
 1542        window: &mut Window,
 1543        cx: &mut Context<Self>,
 1544    ) -> Self {
 1545        debug_assert!(
 1546            display_map.is_none() || mode.is_minimap(),
 1547            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1548        );
 1549
 1550        let full_mode = mode.is_full();
 1551        let diagnostics_max_severity = if full_mode {
 1552            EditorSettings::get_global(cx)
 1553                .diagnostics_max_severity
 1554                .unwrap_or(DiagnosticSeverity::Hint)
 1555        } else {
 1556            DiagnosticSeverity::Off
 1557        };
 1558        let style = window.text_style();
 1559        let font_size = style.font_size.to_pixels(window.rem_size());
 1560        let editor = cx.entity().downgrade();
 1561        let fold_placeholder = FoldPlaceholder {
 1562            constrain_width: true,
 1563            render: Arc::new(move |fold_id, fold_range, cx| {
 1564                let editor = editor.clone();
 1565                div()
 1566                    .id(fold_id)
 1567                    .bg(cx.theme().colors().ghost_element_background)
 1568                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1569                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1570                    .rounded_xs()
 1571                    .size_full()
 1572                    .cursor_pointer()
 1573                    .child("")
 1574                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1575                    .on_click(move |_, _window, cx| {
 1576                        editor
 1577                            .update(cx, |editor, cx| {
 1578                                editor.unfold_ranges(
 1579                                    &[fold_range.start..fold_range.end],
 1580                                    true,
 1581                                    false,
 1582                                    cx,
 1583                                );
 1584                                cx.stop_propagation();
 1585                            })
 1586                            .ok();
 1587                    })
 1588                    .into_any()
 1589            }),
 1590            merge_adjacent: true,
 1591            ..FoldPlaceholder::default()
 1592        };
 1593        let display_map = display_map.unwrap_or_else(|| {
 1594            cx.new(|cx| {
 1595                DisplayMap::new(
 1596                    buffer.clone(),
 1597                    style.font(),
 1598                    font_size,
 1599                    None,
 1600                    FILE_HEADER_HEIGHT,
 1601                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1602                    fold_placeholder,
 1603                    diagnostics_max_severity,
 1604                    cx,
 1605                )
 1606            })
 1607        });
 1608
 1609        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1610
 1611        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1612
 1613        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1614            .then(|| language_settings::SoftWrap::None);
 1615
 1616        let mut project_subscriptions = Vec::new();
 1617        if mode.is_full() {
 1618            if let Some(project) = project.as_ref() {
 1619                project_subscriptions.push(cx.subscribe_in(
 1620                    project,
 1621                    window,
 1622                    |editor, _, event, window, cx| match event {
 1623                        project::Event::RefreshCodeLens => {
 1624                            // we always query lens with actions, without storing them, always refreshing them
 1625                        }
 1626                        project::Event::RefreshInlayHints => {
 1627                            editor
 1628                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1629                        }
 1630                        project::Event::SnippetEdit(id, snippet_edits) => {
 1631                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1632                                let focus_handle = editor.focus_handle(cx);
 1633                                if focus_handle.is_focused(window) {
 1634                                    let snapshot = buffer.read(cx).snapshot();
 1635                                    for (range, snippet) in snippet_edits {
 1636                                        let editor_range =
 1637                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1638                                        editor
 1639                                            .insert_snippet(
 1640                                                &[editor_range],
 1641                                                snippet.clone(),
 1642                                                window,
 1643                                                cx,
 1644                                            )
 1645                                            .ok();
 1646                                    }
 1647                                }
 1648                            }
 1649                        }
 1650                        _ => {}
 1651                    },
 1652                ));
 1653                if let Some(task_inventory) = project
 1654                    .read(cx)
 1655                    .task_store()
 1656                    .read(cx)
 1657                    .task_inventory()
 1658                    .cloned()
 1659                {
 1660                    project_subscriptions.push(cx.observe_in(
 1661                        &task_inventory,
 1662                        window,
 1663                        |editor, _, window, cx| {
 1664                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1665                        },
 1666                    ));
 1667                };
 1668
 1669                project_subscriptions.push(cx.subscribe_in(
 1670                    &project.read(cx).breakpoint_store(),
 1671                    window,
 1672                    |editor, _, event, window, cx| match event {
 1673                        BreakpointStoreEvent::ClearDebugLines => {
 1674                            editor.clear_row_highlights::<ActiveDebugLine>();
 1675                            editor.refresh_inline_values(cx);
 1676                        }
 1677                        BreakpointStoreEvent::SetDebugLine => {
 1678                            if editor.go_to_active_debug_line(window, cx) {
 1679                                cx.stop_propagation();
 1680                            }
 1681
 1682                            editor.refresh_inline_values(cx);
 1683                        }
 1684                        _ => {}
 1685                    },
 1686                ));
 1687            }
 1688        }
 1689
 1690        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1691
 1692        let inlay_hint_settings =
 1693            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1694        let focus_handle = cx.focus_handle();
 1695        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1696            .detach();
 1697        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1698            .detach();
 1699        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1700            .detach();
 1701        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1702            .detach();
 1703
 1704        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1705            Some(false)
 1706        } else {
 1707            None
 1708        };
 1709
 1710        let breakpoint_store = match (&mode, project.as_ref()) {
 1711            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1712            _ => None,
 1713        };
 1714
 1715        let mut code_action_providers = Vec::new();
 1716        let mut load_uncommitted_diff = None;
 1717        if let Some(project) = project.clone() {
 1718            load_uncommitted_diff = Some(
 1719                update_uncommitted_diff_for_buffer(
 1720                    cx.entity(),
 1721                    &project,
 1722                    buffer.read(cx).all_buffers(),
 1723                    buffer.clone(),
 1724                    cx,
 1725                )
 1726                .shared(),
 1727            );
 1728            code_action_providers.push(Rc::new(project) as Rc<_>);
 1729        }
 1730
 1731        let mut this = Self {
 1732            focus_handle,
 1733            show_cursor_when_unfocused: false,
 1734            last_focused_descendant: None,
 1735            buffer: buffer.clone(),
 1736            display_map: display_map.clone(),
 1737            selections,
 1738            scroll_manager: ScrollManager::new(cx),
 1739            columnar_selection_tail: None,
 1740            add_selections_state: None,
 1741            select_next_state: None,
 1742            select_prev_state: None,
 1743            selection_history: SelectionHistory::default(),
 1744            autoclose_regions: Vec::new(),
 1745            snippet_stack: InvalidationStack::default(),
 1746            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1747            ime_transaction: None,
 1748            active_diagnostics: ActiveDiagnostic::None,
 1749            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1750            inline_diagnostics_update: Task::ready(()),
 1751            inline_diagnostics: Vec::new(),
 1752            soft_wrap_mode_override,
 1753            diagnostics_max_severity,
 1754            hard_wrap: None,
 1755            completion_provider: project.clone().map(|project| Box::new(project) as _),
 1756            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1757            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1758            project,
 1759            blink_manager: blink_manager.clone(),
 1760            show_local_selections: true,
 1761            show_scrollbars: full_mode,
 1762            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1763            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1764            show_gutter: mode.is_full(),
 1765            show_line_numbers: None,
 1766            use_relative_line_numbers: None,
 1767            disable_expand_excerpt_buttons: false,
 1768            show_git_diff_gutter: None,
 1769            show_code_actions: None,
 1770            show_runnables: None,
 1771            show_breakpoints: None,
 1772            show_wrap_guides: None,
 1773            show_indent_guides,
 1774            placeholder_text: None,
 1775            highlight_order: 0,
 1776            highlighted_rows: HashMap::default(),
 1777            background_highlights: TreeMap::default(),
 1778            gutter_highlights: TreeMap::default(),
 1779            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1780            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1781            nav_history: None,
 1782            context_menu: RefCell::new(None),
 1783            context_menu_options: None,
 1784            mouse_context_menu: None,
 1785            completion_tasks: Vec::new(),
 1786            inline_blame_popover: None,
 1787            signature_help_state: SignatureHelpState::default(),
 1788            auto_signature_help: None,
 1789            find_all_references_task_sources: Vec::new(),
 1790            next_completion_id: 0,
 1791            next_inlay_id: 0,
 1792            code_action_providers,
 1793            available_code_actions: None,
 1794            code_actions_task: None,
 1795            quick_selection_highlight_task: None,
 1796            debounced_selection_highlight_task: None,
 1797            document_highlights_task: None,
 1798            linked_editing_range_task: None,
 1799            pending_rename: None,
 1800            searchable: true,
 1801            cursor_shape: EditorSettings::get_global(cx)
 1802                .cursor_shape
 1803                .unwrap_or_default(),
 1804            current_line_highlight: None,
 1805            autoindent_mode: Some(AutoindentMode::EachLine),
 1806            collapse_matches: false,
 1807            workspace: None,
 1808            input_enabled: true,
 1809            use_modal_editing: mode.is_full(),
 1810            read_only: mode.is_minimap(),
 1811            use_autoclose: true,
 1812            use_auto_surround: true,
 1813            auto_replace_emoji_shortcode: false,
 1814            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1815            leader_id: None,
 1816            remote_id: None,
 1817            hover_state: HoverState::default(),
 1818            pending_mouse_down: None,
 1819            hovered_link_state: None,
 1820            edit_prediction_provider: None,
 1821            active_inline_completion: None,
 1822            stale_inline_completion_in_menu: None,
 1823            edit_prediction_preview: EditPredictionPreview::Inactive {
 1824                released_too_fast: false,
 1825            },
 1826            inline_diagnostics_enabled: mode.is_full(),
 1827            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1828            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1829
 1830            gutter_hovered: false,
 1831            pixel_position_of_newest_cursor: None,
 1832            last_bounds: None,
 1833            last_position_map: None,
 1834            expect_bounds_change: None,
 1835            gutter_dimensions: GutterDimensions::default(),
 1836            style: None,
 1837            show_cursor_names: false,
 1838            hovered_cursors: HashMap::default(),
 1839            next_editor_action_id: EditorActionId::default(),
 1840            editor_actions: Rc::default(),
 1841            inline_completions_hidden_for_vim_mode: false,
 1842            show_inline_completions_override: None,
 1843            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1844            edit_prediction_settings: EditPredictionSettings::Disabled,
 1845            edit_prediction_indent_conflict: false,
 1846            edit_prediction_requires_modifier_in_indent_conflict: true,
 1847            custom_context_menu: None,
 1848            show_git_blame_gutter: false,
 1849            show_git_blame_inline: false,
 1850            show_selection_menu: None,
 1851            show_git_blame_inline_delay_task: None,
 1852            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1853            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1854            serialize_dirty_buffers: !mode.is_minimap()
 1855                && ProjectSettings::get_global(cx)
 1856                    .session
 1857                    .restore_unsaved_buffers,
 1858            blame: None,
 1859            blame_subscription: None,
 1860            tasks: BTreeMap::default(),
 1861
 1862            breakpoint_store,
 1863            gutter_breakpoint_indicator: (None, None),
 1864            _subscriptions: vec![
 1865                cx.observe(&buffer, Self::on_buffer_changed),
 1866                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1867                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1868                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1869                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1870                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1871                cx.observe_window_activation(window, |editor, window, cx| {
 1872                    let active = window.is_window_active();
 1873                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1874                        if active {
 1875                            blink_manager.enable(cx);
 1876                        } else {
 1877                            blink_manager.disable(cx);
 1878                        }
 1879                    });
 1880                }),
 1881            ],
 1882            tasks_update_task: None,
 1883            linked_edit_ranges: Default::default(),
 1884            in_project_search: false,
 1885            previous_search_ranges: None,
 1886            breadcrumb_header: None,
 1887            focused_block: None,
 1888            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 1889            addons: HashMap::default(),
 1890            registered_buffers: HashMap::default(),
 1891            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 1892            selection_mark_mode: false,
 1893            toggle_fold_multiple_buffers: Task::ready(()),
 1894            serialize_selections: Task::ready(()),
 1895            serialize_folds: Task::ready(()),
 1896            text_style_refinement: None,
 1897            load_diff_task: load_uncommitted_diff,
 1898            temporary_diff_override: false,
 1899            mouse_cursor_hidden: false,
 1900            minimap: None,
 1901            hide_mouse_mode: EditorSettings::get_global(cx)
 1902                .hide_mouse
 1903                .unwrap_or_default(),
 1904            change_list: ChangeList::new(),
 1905            mode,
 1906        };
 1907        if let Some(breakpoints) = this.breakpoint_store.as_ref() {
 1908            this._subscriptions
 1909                .push(cx.observe(breakpoints, |_, _, cx| {
 1910                    cx.notify();
 1911                }));
 1912        }
 1913        this.tasks_update_task = Some(this.refresh_runnables(window, cx));
 1914        this._subscriptions.extend(project_subscriptions);
 1915
 1916        this._subscriptions.push(cx.subscribe_in(
 1917            &cx.entity(),
 1918            window,
 1919            |editor, _, e: &EditorEvent, window, cx| match e {
 1920                EditorEvent::ScrollPositionChanged { local, .. } => {
 1921                    if *local {
 1922                        let new_anchor = editor.scroll_manager.anchor();
 1923                        let snapshot = editor.snapshot(window, cx);
 1924                        editor.update_restoration_data(cx, move |data| {
 1925                            data.scroll_position = (
 1926                                new_anchor.top_row(&snapshot.buffer_snapshot),
 1927                                new_anchor.offset,
 1928                            );
 1929                        });
 1930                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 1931                        editor.inline_blame_popover.take();
 1932                    }
 1933                }
 1934                EditorEvent::Edited { .. } => {
 1935                    if !vim_enabled(cx) {
 1936                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 1937                        let pop_state = editor
 1938                            .change_list
 1939                            .last()
 1940                            .map(|previous| {
 1941                                previous.len() == selections.len()
 1942                                    && previous.iter().enumerate().all(|(ix, p)| {
 1943                                        p.to_display_point(&map).row()
 1944                                            == selections[ix].head().row()
 1945                                    })
 1946                            })
 1947                            .unwrap_or(false);
 1948                        let new_positions = selections
 1949                            .into_iter()
 1950                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 1951                            .collect();
 1952                        editor
 1953                            .change_list
 1954                            .push_to_change_list(pop_state, new_positions);
 1955                    }
 1956                }
 1957                _ => (),
 1958            },
 1959        ));
 1960
 1961        if let Some(dap_store) = this
 1962            .project
 1963            .as_ref()
 1964            .map(|project| project.read(cx).dap_store())
 1965        {
 1966            let weak_editor = cx.weak_entity();
 1967
 1968            this._subscriptions
 1969                .push(
 1970                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 1971                        let session_entity = cx.entity();
 1972                        weak_editor
 1973                            .update(cx, |editor, cx| {
 1974                                editor._subscriptions.push(
 1975                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 1976                                );
 1977                            })
 1978                            .ok();
 1979                    }),
 1980                );
 1981
 1982            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 1983                this._subscriptions
 1984                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 1985            }
 1986        }
 1987
 1988        this.end_selection(window, cx);
 1989        this.scroll_manager.show_scrollbars(window, cx);
 1990        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut this, &buffer, cx);
 1991
 1992        if full_mode {
 1993            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 1994            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 1995
 1996            if this.git_blame_inline_enabled {
 1997                this.start_git_blame_inline(false, window, cx);
 1998            }
 1999
 2000            this.go_to_active_debug_line(window, cx);
 2001
 2002            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2003                if let Some(project) = this.project.as_ref() {
 2004                    let handle = project.update(cx, |project, cx| {
 2005                        project.register_buffer_with_language_servers(&buffer, cx)
 2006                    });
 2007                    this.registered_buffers
 2008                        .insert(buffer.read(cx).remote_id(), handle);
 2009                }
 2010            }
 2011
 2012            this.minimap = this.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2013        }
 2014
 2015        this.report_editor_event("Editor Opened", None, cx);
 2016        this
 2017    }
 2018
 2019    pub fn deploy_mouse_context_menu(
 2020        &mut self,
 2021        position: gpui::Point<Pixels>,
 2022        context_menu: Entity<ContextMenu>,
 2023        window: &mut Window,
 2024        cx: &mut Context<Self>,
 2025    ) {
 2026        self.mouse_context_menu = Some(MouseContextMenu::new(
 2027            self,
 2028            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2029            context_menu,
 2030            window,
 2031            cx,
 2032        ));
 2033    }
 2034
 2035    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2036        self.mouse_context_menu
 2037            .as_ref()
 2038            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2039    }
 2040
 2041    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2042        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2043    }
 2044
 2045    fn key_context_internal(
 2046        &self,
 2047        has_active_edit_prediction: bool,
 2048        window: &Window,
 2049        cx: &App,
 2050    ) -> KeyContext {
 2051        let mut key_context = KeyContext::new_with_defaults();
 2052        key_context.add("Editor");
 2053        let mode = match self.mode {
 2054            EditorMode::SingleLine { .. } => "single_line",
 2055            EditorMode::AutoHeight { .. } => "auto_height",
 2056            EditorMode::Minimap { .. } => "minimap",
 2057            EditorMode::Full { .. } => "full",
 2058        };
 2059
 2060        if EditorSettings::jupyter_enabled(cx) {
 2061            key_context.add("jupyter");
 2062        }
 2063
 2064        key_context.set("mode", mode);
 2065        if self.pending_rename.is_some() {
 2066            key_context.add("renaming");
 2067        }
 2068
 2069        match self.context_menu.borrow().as_ref() {
 2070            Some(CodeContextMenu::Completions(_)) => {
 2071                key_context.add("menu");
 2072                key_context.add("showing_completions");
 2073            }
 2074            Some(CodeContextMenu::CodeActions(_)) => {
 2075                key_context.add("menu");
 2076                key_context.add("showing_code_actions")
 2077            }
 2078            None => {}
 2079        }
 2080
 2081        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2082        if !self.focus_handle(cx).contains_focused(window, cx)
 2083            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2084        {
 2085            for addon in self.addons.values() {
 2086                addon.extend_key_context(&mut key_context, cx)
 2087            }
 2088        }
 2089
 2090        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2091            if let Some(extension) = singleton_buffer
 2092                .read(cx)
 2093                .file()
 2094                .and_then(|file| file.path().extension()?.to_str())
 2095            {
 2096                key_context.set("extension", extension.to_string());
 2097            }
 2098        } else {
 2099            key_context.add("multibuffer");
 2100        }
 2101
 2102        if has_active_edit_prediction {
 2103            if self.edit_prediction_in_conflict() {
 2104                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2105            } else {
 2106                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2107                key_context.add("copilot_suggestion");
 2108            }
 2109        }
 2110
 2111        if self.selection_mark_mode {
 2112            key_context.add("selection_mode");
 2113        }
 2114
 2115        key_context
 2116    }
 2117
 2118    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2119        self.mouse_cursor_hidden = match origin {
 2120            HideMouseCursorOrigin::TypingAction => {
 2121                matches!(
 2122                    self.hide_mouse_mode,
 2123                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2124                )
 2125            }
 2126            HideMouseCursorOrigin::MovementAction => {
 2127                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2128            }
 2129        };
 2130    }
 2131
 2132    pub fn edit_prediction_in_conflict(&self) -> bool {
 2133        if !self.show_edit_predictions_in_menu() {
 2134            return false;
 2135        }
 2136
 2137        let showing_completions = self
 2138            .context_menu
 2139            .borrow()
 2140            .as_ref()
 2141            .map_or(false, |context| {
 2142                matches!(context, CodeContextMenu::Completions(_))
 2143            });
 2144
 2145        showing_completions
 2146            || self.edit_prediction_requires_modifier()
 2147            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2148            // bindings to insert tab characters.
 2149            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2150    }
 2151
 2152    pub fn accept_edit_prediction_keybind(
 2153        &self,
 2154        window: &Window,
 2155        cx: &App,
 2156    ) -> AcceptEditPredictionBinding {
 2157        let key_context = self.key_context_internal(true, window, cx);
 2158        let in_conflict = self.edit_prediction_in_conflict();
 2159
 2160        AcceptEditPredictionBinding(
 2161            window
 2162                .bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2163                .into_iter()
 2164                .filter(|binding| {
 2165                    !in_conflict
 2166                        || binding
 2167                            .keystrokes()
 2168                            .first()
 2169                            .map_or(false, |keystroke| keystroke.modifiers.modified())
 2170                })
 2171                .rev()
 2172                .min_by_key(|binding| {
 2173                    binding
 2174                        .keystrokes()
 2175                        .first()
 2176                        .map_or(u8::MAX, |k| k.modifiers.number_of_modifiers())
 2177                }),
 2178        )
 2179    }
 2180
 2181    pub fn new_file(
 2182        workspace: &mut Workspace,
 2183        _: &workspace::NewFile,
 2184        window: &mut Window,
 2185        cx: &mut Context<Workspace>,
 2186    ) {
 2187        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2188            "Failed to create buffer",
 2189            window,
 2190            cx,
 2191            |e, _, _| match e.error_code() {
 2192                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2193                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2194                e.error_tag("required").unwrap_or("the latest version")
 2195            )),
 2196                _ => None,
 2197            },
 2198        );
 2199    }
 2200
 2201    pub fn new_in_workspace(
 2202        workspace: &mut Workspace,
 2203        window: &mut Window,
 2204        cx: &mut Context<Workspace>,
 2205    ) -> Task<Result<Entity<Editor>>> {
 2206        let project = workspace.project().clone();
 2207        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2208
 2209        cx.spawn_in(window, async move |workspace, cx| {
 2210            let buffer = create.await?;
 2211            workspace.update_in(cx, |workspace, window, cx| {
 2212                let editor =
 2213                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2214                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2215                editor
 2216            })
 2217        })
 2218    }
 2219
 2220    fn new_file_vertical(
 2221        workspace: &mut Workspace,
 2222        _: &workspace::NewFileSplitVertical,
 2223        window: &mut Window,
 2224        cx: &mut Context<Workspace>,
 2225    ) {
 2226        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2227    }
 2228
 2229    fn new_file_horizontal(
 2230        workspace: &mut Workspace,
 2231        _: &workspace::NewFileSplitHorizontal,
 2232        window: &mut Window,
 2233        cx: &mut Context<Workspace>,
 2234    ) {
 2235        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2236    }
 2237
 2238    fn new_file_in_direction(
 2239        workspace: &mut Workspace,
 2240        direction: SplitDirection,
 2241        window: &mut Window,
 2242        cx: &mut Context<Workspace>,
 2243    ) {
 2244        let project = workspace.project().clone();
 2245        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2246
 2247        cx.spawn_in(window, async move |workspace, cx| {
 2248            let buffer = create.await?;
 2249            workspace.update_in(cx, move |workspace, window, cx| {
 2250                workspace.split_item(
 2251                    direction,
 2252                    Box::new(
 2253                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2254                    ),
 2255                    window,
 2256                    cx,
 2257                )
 2258            })?;
 2259            anyhow::Ok(())
 2260        })
 2261        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2262            match e.error_code() {
 2263                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2264                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2265                e.error_tag("required").unwrap_or("the latest version")
 2266            )),
 2267                _ => None,
 2268            }
 2269        });
 2270    }
 2271
 2272    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2273        self.leader_id
 2274    }
 2275
 2276    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2277        &self.buffer
 2278    }
 2279
 2280    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2281        self.workspace.as_ref()?.0.upgrade()
 2282    }
 2283
 2284    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2285        self.buffer().read(cx).title(cx)
 2286    }
 2287
 2288    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2289        let git_blame_gutter_max_author_length = self
 2290            .render_git_blame_gutter(cx)
 2291            .then(|| {
 2292                if let Some(blame) = self.blame.as_ref() {
 2293                    let max_author_length =
 2294                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2295                    Some(max_author_length)
 2296                } else {
 2297                    None
 2298                }
 2299            })
 2300            .flatten();
 2301
 2302        EditorSnapshot {
 2303            mode: self.mode.clone(),
 2304            show_gutter: self.show_gutter,
 2305            show_line_numbers: self.show_line_numbers,
 2306            show_git_diff_gutter: self.show_git_diff_gutter,
 2307            show_runnables: self.show_runnables,
 2308            show_breakpoints: self.show_breakpoints,
 2309            git_blame_gutter_max_author_length,
 2310            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2311            scroll_anchor: self.scroll_manager.anchor(),
 2312            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2313            placeholder_text: self.placeholder_text.clone(),
 2314            is_focused: self.focus_handle.is_focused(window),
 2315            current_line_highlight: self
 2316                .current_line_highlight
 2317                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2318            gutter_hovered: self.gutter_hovered,
 2319        }
 2320    }
 2321
 2322    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2323        self.buffer.read(cx).language_at(point, cx)
 2324    }
 2325
 2326    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2327        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2328    }
 2329
 2330    pub fn active_excerpt(
 2331        &self,
 2332        cx: &App,
 2333    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2334        self.buffer
 2335            .read(cx)
 2336            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2337    }
 2338
 2339    pub fn mode(&self) -> &EditorMode {
 2340        &self.mode
 2341    }
 2342
 2343    pub fn set_mode(&mut self, mode: EditorMode) {
 2344        self.mode = mode;
 2345    }
 2346
 2347    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2348        self.collaboration_hub.as_deref()
 2349    }
 2350
 2351    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2352        self.collaboration_hub = Some(hub);
 2353    }
 2354
 2355    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2356        self.in_project_search = in_project_search;
 2357    }
 2358
 2359    pub fn set_custom_context_menu(
 2360        &mut self,
 2361        f: impl 'static
 2362        + Fn(
 2363            &mut Self,
 2364            DisplayPoint,
 2365            &mut Window,
 2366            &mut Context<Self>,
 2367        ) -> Option<Entity<ui::ContextMenu>>,
 2368    ) {
 2369        self.custom_context_menu = Some(Box::new(f))
 2370    }
 2371
 2372    pub fn set_completion_provider(&mut self, provider: Option<Box<dyn CompletionProvider>>) {
 2373        self.completion_provider = provider;
 2374    }
 2375
 2376    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2377        self.semantics_provider.clone()
 2378    }
 2379
 2380    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2381        self.semantics_provider = provider;
 2382    }
 2383
 2384    pub fn set_edit_prediction_provider<T>(
 2385        &mut self,
 2386        provider: Option<Entity<T>>,
 2387        window: &mut Window,
 2388        cx: &mut Context<Self>,
 2389    ) where
 2390        T: EditPredictionProvider,
 2391    {
 2392        self.edit_prediction_provider =
 2393            provider.map(|provider| RegisteredInlineCompletionProvider {
 2394                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2395                    if this.focus_handle.is_focused(window) {
 2396                        this.update_visible_inline_completion(window, cx);
 2397                    }
 2398                }),
 2399                provider: Arc::new(provider),
 2400            });
 2401        self.update_edit_prediction_settings(cx);
 2402        self.refresh_inline_completion(false, false, window, cx);
 2403    }
 2404
 2405    pub fn placeholder_text(&self) -> Option<&str> {
 2406        self.placeholder_text.as_deref()
 2407    }
 2408
 2409    pub fn set_placeholder_text(
 2410        &mut self,
 2411        placeholder_text: impl Into<Arc<str>>,
 2412        cx: &mut Context<Self>,
 2413    ) {
 2414        let placeholder_text = Some(placeholder_text.into());
 2415        if self.placeholder_text != placeholder_text {
 2416            self.placeholder_text = placeholder_text;
 2417            cx.notify();
 2418        }
 2419    }
 2420
 2421    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2422        self.cursor_shape = cursor_shape;
 2423
 2424        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2425        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2426
 2427        cx.notify();
 2428    }
 2429
 2430    pub fn set_current_line_highlight(
 2431        &mut self,
 2432        current_line_highlight: Option<CurrentLineHighlight>,
 2433    ) {
 2434        self.current_line_highlight = current_line_highlight;
 2435    }
 2436
 2437    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2438        self.collapse_matches = collapse_matches;
 2439    }
 2440
 2441    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2442        let buffers = self.buffer.read(cx).all_buffers();
 2443        let Some(project) = self.project.as_ref() else {
 2444            return;
 2445        };
 2446        project.update(cx, |project, cx| {
 2447            for buffer in buffers {
 2448                self.registered_buffers
 2449                    .entry(buffer.read(cx).remote_id())
 2450                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2451            }
 2452        })
 2453    }
 2454
 2455    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2456        if self.collapse_matches {
 2457            return range.start..range.start;
 2458        }
 2459        range.clone()
 2460    }
 2461
 2462    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2463        if self.display_map.read(cx).clip_at_line_ends != clip {
 2464            self.display_map
 2465                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2466        }
 2467    }
 2468
 2469    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2470        self.input_enabled = input_enabled;
 2471    }
 2472
 2473    pub fn set_inline_completions_hidden_for_vim_mode(
 2474        &mut self,
 2475        hidden: bool,
 2476        window: &mut Window,
 2477        cx: &mut Context<Self>,
 2478    ) {
 2479        if hidden != self.inline_completions_hidden_for_vim_mode {
 2480            self.inline_completions_hidden_for_vim_mode = hidden;
 2481            if hidden {
 2482                self.update_visible_inline_completion(window, cx);
 2483            } else {
 2484                self.refresh_inline_completion(true, false, window, cx);
 2485            }
 2486        }
 2487    }
 2488
 2489    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2490        self.menu_inline_completions_policy = value;
 2491    }
 2492
 2493    pub fn set_autoindent(&mut self, autoindent: bool) {
 2494        if autoindent {
 2495            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2496        } else {
 2497            self.autoindent_mode = None;
 2498        }
 2499    }
 2500
 2501    pub fn read_only(&self, cx: &App) -> bool {
 2502        self.read_only || self.buffer.read(cx).read_only()
 2503    }
 2504
 2505    pub fn set_read_only(&mut self, read_only: bool) {
 2506        self.read_only = read_only;
 2507    }
 2508
 2509    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2510        self.use_autoclose = autoclose;
 2511    }
 2512
 2513    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2514        self.use_auto_surround = auto_surround;
 2515    }
 2516
 2517    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2518        self.auto_replace_emoji_shortcode = auto_replace;
 2519    }
 2520
 2521    pub fn toggle_edit_predictions(
 2522        &mut self,
 2523        _: &ToggleEditPrediction,
 2524        window: &mut Window,
 2525        cx: &mut Context<Self>,
 2526    ) {
 2527        if self.show_inline_completions_override.is_some() {
 2528            self.set_show_edit_predictions(None, window, cx);
 2529        } else {
 2530            let show_edit_predictions = !self.edit_predictions_enabled();
 2531            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2532        }
 2533    }
 2534
 2535    pub fn set_show_edit_predictions(
 2536        &mut self,
 2537        show_edit_predictions: Option<bool>,
 2538        window: &mut Window,
 2539        cx: &mut Context<Self>,
 2540    ) {
 2541        self.show_inline_completions_override = show_edit_predictions;
 2542        self.update_edit_prediction_settings(cx);
 2543
 2544        if let Some(false) = show_edit_predictions {
 2545            self.discard_inline_completion(false, cx);
 2546        } else {
 2547            self.refresh_inline_completion(false, true, window, cx);
 2548        }
 2549    }
 2550
 2551    fn inline_completions_disabled_in_scope(
 2552        &self,
 2553        buffer: &Entity<Buffer>,
 2554        buffer_position: language::Anchor,
 2555        cx: &App,
 2556    ) -> bool {
 2557        let snapshot = buffer.read(cx).snapshot();
 2558        let settings = snapshot.settings_at(buffer_position, cx);
 2559
 2560        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2561            return false;
 2562        };
 2563
 2564        scope.override_name().map_or(false, |scope_name| {
 2565            settings
 2566                .edit_predictions_disabled_in
 2567                .iter()
 2568                .any(|s| s == scope_name)
 2569        })
 2570    }
 2571
 2572    pub fn set_use_modal_editing(&mut self, to: bool) {
 2573        self.use_modal_editing = to;
 2574    }
 2575
 2576    pub fn use_modal_editing(&self) -> bool {
 2577        self.use_modal_editing
 2578    }
 2579
 2580    fn selections_did_change(
 2581        &mut self,
 2582        local: bool,
 2583        old_cursor_position: &Anchor,
 2584        show_completions: bool,
 2585        window: &mut Window,
 2586        cx: &mut Context<Self>,
 2587    ) {
 2588        window.invalidate_character_coordinates();
 2589
 2590        // Copy selections to primary selection buffer
 2591        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2592        if local {
 2593            let selections = self.selections.all::<usize>(cx);
 2594            let buffer_handle = self.buffer.read(cx).read(cx);
 2595
 2596            let mut text = String::new();
 2597            for (index, selection) in selections.iter().enumerate() {
 2598                let text_for_selection = buffer_handle
 2599                    .text_for_range(selection.start..selection.end)
 2600                    .collect::<String>();
 2601
 2602                text.push_str(&text_for_selection);
 2603                if index != selections.len() - 1 {
 2604                    text.push('\n');
 2605                }
 2606            }
 2607
 2608            if !text.is_empty() {
 2609                cx.write_to_primary(ClipboardItem::new_string(text));
 2610            }
 2611        }
 2612
 2613        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2614            self.buffer.update(cx, |buffer, cx| {
 2615                buffer.set_active_selections(
 2616                    &self.selections.disjoint_anchors(),
 2617                    self.selections.line_mode,
 2618                    self.cursor_shape,
 2619                    cx,
 2620                )
 2621            });
 2622        }
 2623        let display_map = self
 2624            .display_map
 2625            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2626        let buffer = &display_map.buffer_snapshot;
 2627        self.add_selections_state = None;
 2628        self.select_next_state = None;
 2629        self.select_prev_state = None;
 2630        self.select_syntax_node_history.try_clear();
 2631        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2632        self.snippet_stack
 2633            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2634        self.take_rename(false, window, cx);
 2635
 2636        let new_cursor_position = self.selections.newest_anchor().head();
 2637
 2638        self.push_to_nav_history(
 2639            *old_cursor_position,
 2640            Some(new_cursor_position.to_point(buffer)),
 2641            false,
 2642            cx,
 2643        );
 2644
 2645        if local {
 2646            let new_cursor_position = self.selections.newest_anchor().head();
 2647            let mut context_menu = self.context_menu.borrow_mut();
 2648            let completion_menu = match context_menu.as_ref() {
 2649                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2650                _ => {
 2651                    *context_menu = None;
 2652                    None
 2653                }
 2654            };
 2655            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2656                if !self.registered_buffers.contains_key(&buffer_id) {
 2657                    if let Some(project) = self.project.as_ref() {
 2658                        project.update(cx, |project, cx| {
 2659                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2660                                return;
 2661                            };
 2662                            self.registered_buffers.insert(
 2663                                buffer_id,
 2664                                project.register_buffer_with_language_servers(&buffer, cx),
 2665                            );
 2666                        })
 2667                    }
 2668                }
 2669            }
 2670
 2671            if let Some(completion_menu) = completion_menu {
 2672                let cursor_position = new_cursor_position.to_offset(buffer);
 2673                let (word_range, kind) =
 2674                    buffer.surrounding_word(completion_menu.initial_position, true);
 2675                if kind == Some(CharKind::Word)
 2676                    && word_range.to_inclusive().contains(&cursor_position)
 2677                {
 2678                    let mut completion_menu = completion_menu.clone();
 2679                    drop(context_menu);
 2680
 2681                    let query = Self::completion_query(buffer, cursor_position);
 2682                    cx.spawn(async move |this, cx| {
 2683                        completion_menu
 2684                            .filter(query.as_deref(), cx.background_executor().clone())
 2685                            .await;
 2686
 2687                        this.update(cx, |this, cx| {
 2688                            let mut context_menu = this.context_menu.borrow_mut();
 2689                            let Some(CodeContextMenu::Completions(menu)) = context_menu.as_ref()
 2690                            else {
 2691                                return;
 2692                            };
 2693
 2694                            if menu.id > completion_menu.id {
 2695                                return;
 2696                            }
 2697
 2698                            *context_menu = Some(CodeContextMenu::Completions(completion_menu));
 2699                            drop(context_menu);
 2700                            cx.notify();
 2701                        })
 2702                    })
 2703                    .detach();
 2704
 2705                    if show_completions {
 2706                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2707                    }
 2708                } else {
 2709                    drop(context_menu);
 2710                    self.hide_context_menu(window, cx);
 2711                }
 2712            } else {
 2713                drop(context_menu);
 2714            }
 2715
 2716            hide_hover(self, cx);
 2717
 2718            if old_cursor_position.to_display_point(&display_map).row()
 2719                != new_cursor_position.to_display_point(&display_map).row()
 2720            {
 2721                self.available_code_actions.take();
 2722            }
 2723            self.refresh_code_actions(window, cx);
 2724            self.refresh_document_highlights(cx);
 2725            self.refresh_selected_text_highlights(false, window, cx);
 2726            refresh_matching_bracket_highlights(self, window, cx);
 2727            self.update_visible_inline_completion(window, cx);
 2728            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2729            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2730            self.inline_blame_popover.take();
 2731            if self.git_blame_inline_enabled {
 2732                self.start_inline_blame_timer(window, cx);
 2733            }
 2734        }
 2735
 2736        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2737        cx.emit(EditorEvent::SelectionsChanged { local });
 2738
 2739        let selections = &self.selections.disjoint;
 2740        if selections.len() == 1 {
 2741            cx.emit(SearchEvent::ActiveMatchChanged)
 2742        }
 2743        if local {
 2744            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2745                let inmemory_selections = selections
 2746                    .iter()
 2747                    .map(|s| {
 2748                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2749                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2750                    })
 2751                    .collect();
 2752                self.update_restoration_data(cx, |data| {
 2753                    data.selections = inmemory_selections;
 2754                });
 2755
 2756                if WorkspaceSettings::get(None, cx).restore_on_startup
 2757                    != RestoreOnStartupBehavior::None
 2758                {
 2759                    if let Some(workspace_id) =
 2760                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2761                    {
 2762                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2763                        let selections = selections.clone();
 2764                        let background_executor = cx.background_executor().clone();
 2765                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2766                        self.serialize_selections = cx.background_spawn(async move {
 2767                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2768                    let db_selections = selections
 2769                        .iter()
 2770                        .map(|selection| {
 2771                            (
 2772                                selection.start.to_offset(&snapshot),
 2773                                selection.end.to_offset(&snapshot),
 2774                            )
 2775                        })
 2776                        .collect();
 2777
 2778                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2779                        .await
 2780                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2781                        .log_err();
 2782                });
 2783                    }
 2784                }
 2785            }
 2786        }
 2787
 2788        cx.notify();
 2789    }
 2790
 2791    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2792        use text::ToOffset as _;
 2793        use text::ToPoint as _;
 2794
 2795        if self.mode.is_minimap()
 2796            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2797        {
 2798            return;
 2799        }
 2800
 2801        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2802            return;
 2803        };
 2804
 2805        let snapshot = singleton.read(cx).snapshot();
 2806        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2807            let display_snapshot = display_map.snapshot(cx);
 2808
 2809            display_snapshot
 2810                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2811                .map(|fold| {
 2812                    fold.range.start.text_anchor.to_point(&snapshot)
 2813                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2814                })
 2815                .collect()
 2816        });
 2817        self.update_restoration_data(cx, |data| {
 2818            data.folds = inmemory_folds;
 2819        });
 2820
 2821        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2822            return;
 2823        };
 2824        let background_executor = cx.background_executor().clone();
 2825        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2826        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2827            display_map
 2828                .snapshot(cx)
 2829                .folds_in_range(0..snapshot.len())
 2830                .map(|fold| {
 2831                    (
 2832                        fold.range.start.text_anchor.to_offset(&snapshot),
 2833                        fold.range.end.text_anchor.to_offset(&snapshot),
 2834                    )
 2835                })
 2836                .collect()
 2837        });
 2838        self.serialize_folds = cx.background_spawn(async move {
 2839            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2840            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2841                .await
 2842                .with_context(|| {
 2843                    format!(
 2844                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2845                    )
 2846                })
 2847                .log_err();
 2848        });
 2849    }
 2850
 2851    pub fn sync_selections(
 2852        &mut self,
 2853        other: Entity<Editor>,
 2854        cx: &mut Context<Self>,
 2855    ) -> gpui::Subscription {
 2856        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2857        self.selections.change_with(cx, |selections| {
 2858            selections.select_anchors(other_selections);
 2859        });
 2860
 2861        let other_subscription =
 2862            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2863                EditorEvent::SelectionsChanged { local: true } => {
 2864                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2865                    if other_selections.is_empty() {
 2866                        return;
 2867                    }
 2868                    this.selections.change_with(cx, |selections| {
 2869                        selections.select_anchors(other_selections);
 2870                    });
 2871                }
 2872                _ => {}
 2873            });
 2874
 2875        let this_subscription =
 2876            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2877                EditorEvent::SelectionsChanged { local: true } => {
 2878                    let these_selections = this.selections.disjoint.to_vec();
 2879                    if these_selections.is_empty() {
 2880                        return;
 2881                    }
 2882                    other.update(cx, |other_editor, cx| {
 2883                        other_editor.selections.change_with(cx, |selections| {
 2884                            selections.select_anchors(these_selections);
 2885                        })
 2886                    });
 2887                }
 2888                _ => {}
 2889            });
 2890
 2891        Subscription::join(other_subscription, this_subscription)
 2892    }
 2893
 2894    pub fn change_selections<R>(
 2895        &mut self,
 2896        autoscroll: Option<Autoscroll>,
 2897        window: &mut Window,
 2898        cx: &mut Context<Self>,
 2899        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2900    ) -> R {
 2901        self.change_selections_inner(autoscroll, true, window, cx, change)
 2902    }
 2903
 2904    fn change_selections_inner<R>(
 2905        &mut self,
 2906        autoscroll: Option<Autoscroll>,
 2907        request_completions: bool,
 2908        window: &mut Window,
 2909        cx: &mut Context<Self>,
 2910        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2911    ) -> R {
 2912        let old_cursor_position = self.selections.newest_anchor().head();
 2913        self.push_to_selection_history();
 2914
 2915        let (changed, result) = self.selections.change_with(cx, change);
 2916
 2917        if changed {
 2918            if let Some(autoscroll) = autoscroll {
 2919                self.request_autoscroll(autoscroll, cx);
 2920            }
 2921            self.selections_did_change(true, &old_cursor_position, request_completions, window, cx);
 2922
 2923            if self.should_open_signature_help_automatically(
 2924                &old_cursor_position,
 2925                self.signature_help_state.backspace_pressed(),
 2926                cx,
 2927            ) {
 2928                self.show_signature_help(&ShowSignatureHelp, window, cx);
 2929            }
 2930            self.signature_help_state.set_backspace_pressed(false);
 2931        }
 2932
 2933        result
 2934    }
 2935
 2936    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2937    where
 2938        I: IntoIterator<Item = (Range<S>, T)>,
 2939        S: ToOffset,
 2940        T: Into<Arc<str>>,
 2941    {
 2942        if self.read_only(cx) {
 2943            return;
 2944        }
 2945
 2946        self.buffer
 2947            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 2948    }
 2949
 2950    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2951    where
 2952        I: IntoIterator<Item = (Range<S>, T)>,
 2953        S: ToOffset,
 2954        T: Into<Arc<str>>,
 2955    {
 2956        if self.read_only(cx) {
 2957            return;
 2958        }
 2959
 2960        self.buffer.update(cx, |buffer, cx| {
 2961            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 2962        });
 2963    }
 2964
 2965    pub fn edit_with_block_indent<I, S, T>(
 2966        &mut self,
 2967        edits: I,
 2968        original_indent_columns: Vec<Option<u32>>,
 2969        cx: &mut Context<Self>,
 2970    ) where
 2971        I: IntoIterator<Item = (Range<S>, T)>,
 2972        S: ToOffset,
 2973        T: Into<Arc<str>>,
 2974    {
 2975        if self.read_only(cx) {
 2976            return;
 2977        }
 2978
 2979        self.buffer.update(cx, |buffer, cx| {
 2980            buffer.edit(
 2981                edits,
 2982                Some(AutoindentMode::Block {
 2983                    original_indent_columns,
 2984                }),
 2985                cx,
 2986            )
 2987        });
 2988    }
 2989
 2990    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 2991        self.hide_context_menu(window, cx);
 2992
 2993        match phase {
 2994            SelectPhase::Begin {
 2995                position,
 2996                add,
 2997                click_count,
 2998            } => self.begin_selection(position, add, click_count, window, cx),
 2999            SelectPhase::BeginColumnar {
 3000                position,
 3001                goal_column,
 3002                reset,
 3003            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3004            SelectPhase::Extend {
 3005                position,
 3006                click_count,
 3007            } => self.extend_selection(position, click_count, window, cx),
 3008            SelectPhase::Update {
 3009                position,
 3010                goal_column,
 3011                scroll_delta,
 3012            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3013            SelectPhase::End => self.end_selection(window, cx),
 3014        }
 3015    }
 3016
 3017    fn extend_selection(
 3018        &mut self,
 3019        position: DisplayPoint,
 3020        click_count: usize,
 3021        window: &mut Window,
 3022        cx: &mut Context<Self>,
 3023    ) {
 3024        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3025        let tail = self.selections.newest::<usize>(cx).tail();
 3026        self.begin_selection(position, false, click_count, window, cx);
 3027
 3028        let position = position.to_offset(&display_map, Bias::Left);
 3029        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3030
 3031        let mut pending_selection = self
 3032            .selections
 3033            .pending_anchor()
 3034            .expect("extend_selection not called with pending selection");
 3035        if position >= tail {
 3036            pending_selection.start = tail_anchor;
 3037        } else {
 3038            pending_selection.end = tail_anchor;
 3039            pending_selection.reversed = true;
 3040        }
 3041
 3042        let mut pending_mode = self.selections.pending_mode().unwrap();
 3043        match &mut pending_mode {
 3044            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3045            _ => {}
 3046        }
 3047
 3048        let auto_scroll = EditorSettings::get_global(cx).autoscroll_on_clicks;
 3049
 3050        self.change_selections(auto_scroll.then(Autoscroll::fit), window, cx, |s| {
 3051            s.set_pending(pending_selection, pending_mode)
 3052        });
 3053    }
 3054
 3055    fn begin_selection(
 3056        &mut self,
 3057        position: DisplayPoint,
 3058        add: bool,
 3059        click_count: usize,
 3060        window: &mut Window,
 3061        cx: &mut Context<Self>,
 3062    ) {
 3063        if !self.focus_handle.is_focused(window) {
 3064            self.last_focused_descendant = None;
 3065            window.focus(&self.focus_handle);
 3066        }
 3067
 3068        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3069        let buffer = &display_map.buffer_snapshot;
 3070        let position = display_map.clip_point(position, Bias::Left);
 3071
 3072        let start;
 3073        let end;
 3074        let mode;
 3075        let mut auto_scroll;
 3076        match click_count {
 3077            1 => {
 3078                start = buffer.anchor_before(position.to_point(&display_map));
 3079                end = start;
 3080                mode = SelectMode::Character;
 3081                auto_scroll = true;
 3082            }
 3083            2 => {
 3084                let range = movement::surrounding_word(&display_map, position);
 3085                start = buffer.anchor_before(range.start.to_point(&display_map));
 3086                end = buffer.anchor_before(range.end.to_point(&display_map));
 3087                mode = SelectMode::Word(start..end);
 3088                auto_scroll = true;
 3089            }
 3090            3 => {
 3091                let position = display_map
 3092                    .clip_point(position, Bias::Left)
 3093                    .to_point(&display_map);
 3094                let line_start = display_map.prev_line_boundary(position).0;
 3095                let next_line_start = buffer.clip_point(
 3096                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3097                    Bias::Left,
 3098                );
 3099                start = buffer.anchor_before(line_start);
 3100                end = buffer.anchor_before(next_line_start);
 3101                mode = SelectMode::Line(start..end);
 3102                auto_scroll = true;
 3103            }
 3104            _ => {
 3105                start = buffer.anchor_before(0);
 3106                end = buffer.anchor_before(buffer.len());
 3107                mode = SelectMode::All;
 3108                auto_scroll = false;
 3109            }
 3110        }
 3111        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3112
 3113        let point_to_delete: Option<usize> = {
 3114            let selected_points: Vec<Selection<Point>> =
 3115                self.selections.disjoint_in_range(start..end, cx);
 3116
 3117            if !add || click_count > 1 {
 3118                None
 3119            } else if !selected_points.is_empty() {
 3120                Some(selected_points[0].id)
 3121            } else {
 3122                let clicked_point_already_selected =
 3123                    self.selections.disjoint.iter().find(|selection| {
 3124                        selection.start.to_point(buffer) == start.to_point(buffer)
 3125                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3126                    });
 3127
 3128                clicked_point_already_selected.map(|selection| selection.id)
 3129            }
 3130        };
 3131
 3132        let selections_count = self.selections.count();
 3133
 3134        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3135            if let Some(point_to_delete) = point_to_delete {
 3136                s.delete(point_to_delete);
 3137
 3138                if selections_count == 1 {
 3139                    s.set_pending_anchor_range(start..end, mode);
 3140                }
 3141            } else {
 3142                if !add {
 3143                    s.clear_disjoint();
 3144                }
 3145
 3146                s.set_pending_anchor_range(start..end, mode);
 3147            }
 3148        });
 3149    }
 3150
 3151    fn begin_columnar_selection(
 3152        &mut self,
 3153        position: DisplayPoint,
 3154        goal_column: u32,
 3155        reset: bool,
 3156        window: &mut Window,
 3157        cx: &mut Context<Self>,
 3158    ) {
 3159        if !self.focus_handle.is_focused(window) {
 3160            self.last_focused_descendant = None;
 3161            window.focus(&self.focus_handle);
 3162        }
 3163
 3164        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3165
 3166        if reset {
 3167            let pointer_position = display_map
 3168                .buffer_snapshot
 3169                .anchor_before(position.to_point(&display_map));
 3170
 3171            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3172                s.clear_disjoint();
 3173                s.set_pending_anchor_range(
 3174                    pointer_position..pointer_position,
 3175                    SelectMode::Character,
 3176                );
 3177            });
 3178        }
 3179
 3180        let tail = self.selections.newest::<Point>(cx).tail();
 3181        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3182
 3183        if !reset {
 3184            self.select_columns(
 3185                tail.to_display_point(&display_map),
 3186                position,
 3187                goal_column,
 3188                &display_map,
 3189                window,
 3190                cx,
 3191            );
 3192        }
 3193    }
 3194
 3195    fn update_selection(
 3196        &mut self,
 3197        position: DisplayPoint,
 3198        goal_column: u32,
 3199        scroll_delta: gpui::Point<f32>,
 3200        window: &mut Window,
 3201        cx: &mut Context<Self>,
 3202    ) {
 3203        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3204
 3205        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3206            let tail = tail.to_display_point(&display_map);
 3207            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3208        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3209            let buffer = self.buffer.read(cx).snapshot(cx);
 3210            let head;
 3211            let tail;
 3212            let mode = self.selections.pending_mode().unwrap();
 3213            match &mode {
 3214                SelectMode::Character => {
 3215                    head = position.to_point(&display_map);
 3216                    tail = pending.tail().to_point(&buffer);
 3217                }
 3218                SelectMode::Word(original_range) => {
 3219                    let original_display_range = original_range.start.to_display_point(&display_map)
 3220                        ..original_range.end.to_display_point(&display_map);
 3221                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3222                        ..original_display_range.end.to_point(&display_map);
 3223                    if movement::is_inside_word(&display_map, position)
 3224                        || original_display_range.contains(&position)
 3225                    {
 3226                        let word_range = movement::surrounding_word(&display_map, position);
 3227                        if word_range.start < original_display_range.start {
 3228                            head = word_range.start.to_point(&display_map);
 3229                        } else {
 3230                            head = word_range.end.to_point(&display_map);
 3231                        }
 3232                    } else {
 3233                        head = position.to_point(&display_map);
 3234                    }
 3235
 3236                    if head <= original_buffer_range.start {
 3237                        tail = original_buffer_range.end;
 3238                    } else {
 3239                        tail = original_buffer_range.start;
 3240                    }
 3241                }
 3242                SelectMode::Line(original_range) => {
 3243                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3244
 3245                    let position = display_map
 3246                        .clip_point(position, Bias::Left)
 3247                        .to_point(&display_map);
 3248                    let line_start = display_map.prev_line_boundary(position).0;
 3249                    let next_line_start = buffer.clip_point(
 3250                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3251                        Bias::Left,
 3252                    );
 3253
 3254                    if line_start < original_range.start {
 3255                        head = line_start
 3256                    } else {
 3257                        head = next_line_start
 3258                    }
 3259
 3260                    if head <= original_range.start {
 3261                        tail = original_range.end;
 3262                    } else {
 3263                        tail = original_range.start;
 3264                    }
 3265                }
 3266                SelectMode::All => {
 3267                    return;
 3268                }
 3269            };
 3270
 3271            if head < tail {
 3272                pending.start = buffer.anchor_before(head);
 3273                pending.end = buffer.anchor_before(tail);
 3274                pending.reversed = true;
 3275            } else {
 3276                pending.start = buffer.anchor_before(tail);
 3277                pending.end = buffer.anchor_before(head);
 3278                pending.reversed = false;
 3279            }
 3280
 3281            self.change_selections(None, window, cx, |s| {
 3282                s.set_pending(pending, mode);
 3283            });
 3284        } else {
 3285            log::error!("update_selection dispatched with no pending selection");
 3286            return;
 3287        }
 3288
 3289        self.apply_scroll_delta(scroll_delta, window, cx);
 3290        cx.notify();
 3291    }
 3292
 3293    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3294        self.columnar_selection_tail.take();
 3295        if self.selections.pending_anchor().is_some() {
 3296            let selections = self.selections.all::<usize>(cx);
 3297            self.change_selections(None, window, cx, |s| {
 3298                s.select(selections);
 3299                s.clear_pending();
 3300            });
 3301        }
 3302    }
 3303
 3304    fn select_columns(
 3305        &mut self,
 3306        tail: DisplayPoint,
 3307        head: DisplayPoint,
 3308        goal_column: u32,
 3309        display_map: &DisplaySnapshot,
 3310        window: &mut Window,
 3311        cx: &mut Context<Self>,
 3312    ) {
 3313        let start_row = cmp::min(tail.row(), head.row());
 3314        let end_row = cmp::max(tail.row(), head.row());
 3315        let start_column = cmp::min(tail.column(), goal_column);
 3316        let end_column = cmp::max(tail.column(), goal_column);
 3317        let reversed = start_column < tail.column();
 3318
 3319        let selection_ranges = (start_row.0..=end_row.0)
 3320            .map(DisplayRow)
 3321            .filter_map(|row| {
 3322                if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
 3323                    let start = display_map
 3324                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3325                        .to_point(display_map);
 3326                    let end = display_map
 3327                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3328                        .to_point(display_map);
 3329                    if reversed {
 3330                        Some(end..start)
 3331                    } else {
 3332                        Some(start..end)
 3333                    }
 3334                } else {
 3335                    None
 3336                }
 3337            })
 3338            .collect::<Vec<_>>();
 3339
 3340        self.change_selections(None, window, cx, |s| {
 3341            s.select_ranges(selection_ranges);
 3342        });
 3343        cx.notify();
 3344    }
 3345
 3346    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3347        self.selections
 3348            .all_adjusted(cx)
 3349            .iter()
 3350            .any(|selection| !selection.is_empty())
 3351    }
 3352
 3353    pub fn has_pending_nonempty_selection(&self) -> bool {
 3354        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3355            Some(Selection { start, end, .. }) => start != end,
 3356            None => false,
 3357        };
 3358
 3359        pending_nonempty_selection
 3360            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3361    }
 3362
 3363    pub fn has_pending_selection(&self) -> bool {
 3364        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3365    }
 3366
 3367    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3368        self.selection_mark_mode = false;
 3369
 3370        if self.clear_expanded_diff_hunks(cx) {
 3371            cx.notify();
 3372            return;
 3373        }
 3374        if self.dismiss_menus_and_popups(true, window, cx) {
 3375            return;
 3376        }
 3377
 3378        if self.mode.is_full()
 3379            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3380        {
 3381            return;
 3382        }
 3383
 3384        cx.propagate();
 3385    }
 3386
 3387    pub fn dismiss_menus_and_popups(
 3388        &mut self,
 3389        is_user_requested: bool,
 3390        window: &mut Window,
 3391        cx: &mut Context<Self>,
 3392    ) -> bool {
 3393        if self.take_rename(false, window, cx).is_some() {
 3394            return true;
 3395        }
 3396
 3397        if hide_hover(self, cx) {
 3398            return true;
 3399        }
 3400
 3401        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3402            return true;
 3403        }
 3404
 3405        if self.hide_context_menu(window, cx).is_some() {
 3406            return true;
 3407        }
 3408
 3409        if self.mouse_context_menu.take().is_some() {
 3410            return true;
 3411        }
 3412
 3413        if is_user_requested && self.discard_inline_completion(true, cx) {
 3414            return true;
 3415        }
 3416
 3417        if self.snippet_stack.pop().is_some() {
 3418            return true;
 3419        }
 3420
 3421        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3422            self.dismiss_diagnostics(cx);
 3423            return true;
 3424        }
 3425
 3426        false
 3427    }
 3428
 3429    fn linked_editing_ranges_for(
 3430        &self,
 3431        selection: Range<text::Anchor>,
 3432        cx: &App,
 3433    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3434        if self.linked_edit_ranges.is_empty() {
 3435            return None;
 3436        }
 3437        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3438            selection.end.buffer_id.and_then(|end_buffer_id| {
 3439                if selection.start.buffer_id != Some(end_buffer_id) {
 3440                    return None;
 3441                }
 3442                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3443                let snapshot = buffer.read(cx).snapshot();
 3444                self.linked_edit_ranges
 3445                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3446                    .map(|ranges| (ranges, snapshot, buffer))
 3447            })?;
 3448        use text::ToOffset as TO;
 3449        // find offset from the start of current range to current cursor position
 3450        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3451
 3452        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3453        let start_difference = start_offset - start_byte_offset;
 3454        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3455        let end_difference = end_offset - start_byte_offset;
 3456        // Current range has associated linked ranges.
 3457        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3458        for range in linked_ranges.iter() {
 3459            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3460            let end_offset = start_offset + end_difference;
 3461            let start_offset = start_offset + start_difference;
 3462            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3463                continue;
 3464            }
 3465            if self.selections.disjoint_anchor_ranges().any(|s| {
 3466                if s.start.buffer_id != selection.start.buffer_id
 3467                    || s.end.buffer_id != selection.end.buffer_id
 3468                {
 3469                    return false;
 3470                }
 3471                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3472                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3473            }) {
 3474                continue;
 3475            }
 3476            let start = buffer_snapshot.anchor_after(start_offset);
 3477            let end = buffer_snapshot.anchor_after(end_offset);
 3478            linked_edits
 3479                .entry(buffer.clone())
 3480                .or_default()
 3481                .push(start..end);
 3482        }
 3483        Some(linked_edits)
 3484    }
 3485
 3486    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3487        let text: Arc<str> = text.into();
 3488
 3489        if self.read_only(cx) {
 3490            return;
 3491        }
 3492
 3493        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3494
 3495        let selections = self.selections.all_adjusted(cx);
 3496        let mut bracket_inserted = false;
 3497        let mut edits = Vec::new();
 3498        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3499        let mut new_selections = Vec::with_capacity(selections.len());
 3500        let mut new_autoclose_regions = Vec::new();
 3501        let snapshot = self.buffer.read(cx).read(cx);
 3502        let mut clear_linked_edit_ranges = false;
 3503
 3504        for (selection, autoclose_region) in
 3505            self.selections_with_autoclose_regions(selections, &snapshot)
 3506        {
 3507            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3508                // Determine if the inserted text matches the opening or closing
 3509                // bracket of any of this language's bracket pairs.
 3510                let mut bracket_pair = None;
 3511                let mut is_bracket_pair_start = false;
 3512                let mut is_bracket_pair_end = false;
 3513                if !text.is_empty() {
 3514                    let mut bracket_pair_matching_end = None;
 3515                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3516                    //  and they are removing the character that triggered IME popup.
 3517                    for (pair, enabled) in scope.brackets() {
 3518                        if !pair.close && !pair.surround {
 3519                            continue;
 3520                        }
 3521
 3522                        if enabled && pair.start.ends_with(text.as_ref()) {
 3523                            let prefix_len = pair.start.len() - text.len();
 3524                            let preceding_text_matches_prefix = prefix_len == 0
 3525                                || (selection.start.column >= (prefix_len as u32)
 3526                                    && snapshot.contains_str_at(
 3527                                        Point::new(
 3528                                            selection.start.row,
 3529                                            selection.start.column - (prefix_len as u32),
 3530                                        ),
 3531                                        &pair.start[..prefix_len],
 3532                                    ));
 3533                            if preceding_text_matches_prefix {
 3534                                bracket_pair = Some(pair.clone());
 3535                                is_bracket_pair_start = true;
 3536                                break;
 3537                            }
 3538                        }
 3539                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3540                        {
 3541                            // take first bracket pair matching end, but don't break in case a later bracket
 3542                            // pair matches start
 3543                            bracket_pair_matching_end = Some(pair.clone());
 3544                        }
 3545                    }
 3546                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3547                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3548                        is_bracket_pair_end = true;
 3549                    }
 3550                }
 3551
 3552                if let Some(bracket_pair) = bracket_pair {
 3553                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3554                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3555                    let auto_surround =
 3556                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3557                    if selection.is_empty() {
 3558                        if is_bracket_pair_start {
 3559                            // If the inserted text is a suffix of an opening bracket and the
 3560                            // selection is preceded by the rest of the opening bracket, then
 3561                            // insert the closing bracket.
 3562                            let following_text_allows_autoclose = snapshot
 3563                                .chars_at(selection.start)
 3564                                .next()
 3565                                .map_or(true, |c| scope.should_autoclose_before(c));
 3566
 3567                            let preceding_text_allows_autoclose = selection.start.column == 0
 3568                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3569                                    true,
 3570                                    |c| {
 3571                                        bracket_pair.start != bracket_pair.end
 3572                                            || !snapshot
 3573                                                .char_classifier_at(selection.start)
 3574                                                .is_word(c)
 3575                                    },
 3576                                );
 3577
 3578                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3579                                && bracket_pair.start.len() == 1
 3580                            {
 3581                                let target = bracket_pair.start.chars().next().unwrap();
 3582                                let current_line_count = snapshot
 3583                                    .reversed_chars_at(selection.start)
 3584                                    .take_while(|&c| c != '\n')
 3585                                    .filter(|&c| c == target)
 3586                                    .count();
 3587                                current_line_count % 2 == 1
 3588                            } else {
 3589                                false
 3590                            };
 3591
 3592                            if autoclose
 3593                                && bracket_pair.close
 3594                                && following_text_allows_autoclose
 3595                                && preceding_text_allows_autoclose
 3596                                && !is_closing_quote
 3597                            {
 3598                                let anchor = snapshot.anchor_before(selection.end);
 3599                                new_selections.push((selection.map(|_| anchor), text.len()));
 3600                                new_autoclose_regions.push((
 3601                                    anchor,
 3602                                    text.len(),
 3603                                    selection.id,
 3604                                    bracket_pair.clone(),
 3605                                ));
 3606                                edits.push((
 3607                                    selection.range(),
 3608                                    format!("{}{}", text, bracket_pair.end).into(),
 3609                                ));
 3610                                bracket_inserted = true;
 3611                                continue;
 3612                            }
 3613                        }
 3614
 3615                        if let Some(region) = autoclose_region {
 3616                            // If the selection is followed by an auto-inserted closing bracket,
 3617                            // then don't insert that closing bracket again; just move the selection
 3618                            // past the closing bracket.
 3619                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3620                                && text.as_ref() == region.pair.end.as_str();
 3621                            if should_skip {
 3622                                let anchor = snapshot.anchor_after(selection.end);
 3623                                new_selections
 3624                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3625                                continue;
 3626                            }
 3627                        }
 3628
 3629                        let always_treat_brackets_as_autoclosed = snapshot
 3630                            .language_settings_at(selection.start, cx)
 3631                            .always_treat_brackets_as_autoclosed;
 3632                        if always_treat_brackets_as_autoclosed
 3633                            && is_bracket_pair_end
 3634                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3635                        {
 3636                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3637                            // and the inserted text is a closing bracket and the selection is followed
 3638                            // by the closing bracket then move the selection past the closing bracket.
 3639                            let anchor = snapshot.anchor_after(selection.end);
 3640                            new_selections.push((selection.map(|_| anchor), text.len()));
 3641                            continue;
 3642                        }
 3643                    }
 3644                    // If an opening bracket is 1 character long and is typed while
 3645                    // text is selected, then surround that text with the bracket pair.
 3646                    else if auto_surround
 3647                        && bracket_pair.surround
 3648                        && is_bracket_pair_start
 3649                        && bracket_pair.start.chars().count() == 1
 3650                    {
 3651                        edits.push((selection.start..selection.start, text.clone()));
 3652                        edits.push((
 3653                            selection.end..selection.end,
 3654                            bracket_pair.end.as_str().into(),
 3655                        ));
 3656                        bracket_inserted = true;
 3657                        new_selections.push((
 3658                            Selection {
 3659                                id: selection.id,
 3660                                start: snapshot.anchor_after(selection.start),
 3661                                end: snapshot.anchor_before(selection.end),
 3662                                reversed: selection.reversed,
 3663                                goal: selection.goal,
 3664                            },
 3665                            0,
 3666                        ));
 3667                        continue;
 3668                    }
 3669                }
 3670            }
 3671
 3672            if self.auto_replace_emoji_shortcode
 3673                && selection.is_empty()
 3674                && text.as_ref().ends_with(':')
 3675            {
 3676                if let Some(possible_emoji_short_code) =
 3677                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3678                {
 3679                    if !possible_emoji_short_code.is_empty() {
 3680                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3681                            let emoji_shortcode_start = Point::new(
 3682                                selection.start.row,
 3683                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3684                            );
 3685
 3686                            // Remove shortcode from buffer
 3687                            edits.push((
 3688                                emoji_shortcode_start..selection.start,
 3689                                "".to_string().into(),
 3690                            ));
 3691                            new_selections.push((
 3692                                Selection {
 3693                                    id: selection.id,
 3694                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3695                                    end: snapshot.anchor_before(selection.start),
 3696                                    reversed: selection.reversed,
 3697                                    goal: selection.goal,
 3698                                },
 3699                                0,
 3700                            ));
 3701
 3702                            // Insert emoji
 3703                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3704                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3705                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3706
 3707                            continue;
 3708                        }
 3709                    }
 3710                }
 3711            }
 3712
 3713            // If not handling any auto-close operation, then just replace the selected
 3714            // text with the given input and move the selection to the end of the
 3715            // newly inserted text.
 3716            let anchor = snapshot.anchor_after(selection.end);
 3717            if !self.linked_edit_ranges.is_empty() {
 3718                let start_anchor = snapshot.anchor_before(selection.start);
 3719
 3720                let is_word_char = text.chars().next().map_or(true, |char| {
 3721                    let classifier = snapshot
 3722                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3723                        .ignore_punctuation(true);
 3724                    classifier.is_word(char)
 3725                });
 3726
 3727                if is_word_char {
 3728                    if let Some(ranges) = self
 3729                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3730                    {
 3731                        for (buffer, edits) in ranges {
 3732                            linked_edits
 3733                                .entry(buffer.clone())
 3734                                .or_default()
 3735                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3736                        }
 3737                    }
 3738                } else {
 3739                    clear_linked_edit_ranges = true;
 3740                }
 3741            }
 3742
 3743            new_selections.push((selection.map(|_| anchor), 0));
 3744            edits.push((selection.start..selection.end, text.clone()));
 3745        }
 3746
 3747        drop(snapshot);
 3748
 3749        self.transact(window, cx, |this, window, cx| {
 3750            if clear_linked_edit_ranges {
 3751                this.linked_edit_ranges.clear();
 3752            }
 3753            let initial_buffer_versions =
 3754                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3755
 3756            this.buffer.update(cx, |buffer, cx| {
 3757                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3758            });
 3759            for (buffer, edits) in linked_edits {
 3760                buffer.update(cx, |buffer, cx| {
 3761                    let snapshot = buffer.snapshot();
 3762                    let edits = edits
 3763                        .into_iter()
 3764                        .map(|(range, text)| {
 3765                            use text::ToPoint as TP;
 3766                            let end_point = TP::to_point(&range.end, &snapshot);
 3767                            let start_point = TP::to_point(&range.start, &snapshot);
 3768                            (start_point..end_point, text)
 3769                        })
 3770                        .sorted_by_key(|(range, _)| range.start);
 3771                    buffer.edit(edits, None, cx);
 3772                })
 3773            }
 3774            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3775            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3776            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3777            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3778                .zip(new_selection_deltas)
 3779                .map(|(selection, delta)| Selection {
 3780                    id: selection.id,
 3781                    start: selection.start + delta,
 3782                    end: selection.end + delta,
 3783                    reversed: selection.reversed,
 3784                    goal: SelectionGoal::None,
 3785                })
 3786                .collect::<Vec<_>>();
 3787
 3788            let mut i = 0;
 3789            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3790                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3791                let start = map.buffer_snapshot.anchor_before(position);
 3792                let end = map.buffer_snapshot.anchor_after(position);
 3793                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3794                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3795                        Ordering::Less => i += 1,
 3796                        Ordering::Greater => break,
 3797                        Ordering::Equal => {
 3798                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 3799                                Ordering::Less => i += 1,
 3800                                Ordering::Equal => break,
 3801                                Ordering::Greater => break,
 3802                            }
 3803                        }
 3804                    }
 3805                }
 3806                this.autoclose_regions.insert(
 3807                    i,
 3808                    AutocloseRegion {
 3809                        selection_id,
 3810                        range: start..end,
 3811                        pair,
 3812                    },
 3813                );
 3814            }
 3815
 3816            let had_active_inline_completion = this.has_active_inline_completion();
 3817            this.change_selections_inner(Some(Autoscroll::fit()), false, window, cx, |s| {
 3818                s.select(new_selections)
 3819            });
 3820
 3821            if !bracket_inserted {
 3822                if let Some(on_type_format_task) =
 3823                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 3824                {
 3825                    on_type_format_task.detach_and_log_err(cx);
 3826                }
 3827            }
 3828
 3829            let editor_settings = EditorSettings::get_global(cx);
 3830            if bracket_inserted
 3831                && (editor_settings.auto_signature_help
 3832                    || editor_settings.show_signature_help_after_edits)
 3833            {
 3834                this.show_signature_help(&ShowSignatureHelp, window, cx);
 3835            }
 3836
 3837            let trigger_in_words =
 3838                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 3839            if this.hard_wrap.is_some() {
 3840                let latest: Range<Point> = this.selections.newest(cx).range();
 3841                if latest.is_empty()
 3842                    && this
 3843                        .buffer()
 3844                        .read(cx)
 3845                        .snapshot(cx)
 3846                        .line_len(MultiBufferRow(latest.start.row))
 3847                        == latest.start.column
 3848                {
 3849                    this.rewrap_impl(
 3850                        RewrapOptions {
 3851                            override_language_settings: true,
 3852                            preserve_existing_whitespace: true,
 3853                        },
 3854                        cx,
 3855                    )
 3856                }
 3857            }
 3858            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 3859            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 3860            this.refresh_inline_completion(true, false, window, cx);
 3861            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 3862        });
 3863    }
 3864
 3865    fn find_possible_emoji_shortcode_at_position(
 3866        snapshot: &MultiBufferSnapshot,
 3867        position: Point,
 3868    ) -> Option<String> {
 3869        let mut chars = Vec::new();
 3870        let mut found_colon = false;
 3871        for char in snapshot.reversed_chars_at(position).take(100) {
 3872            // Found a possible emoji shortcode in the middle of the buffer
 3873            if found_colon {
 3874                if char.is_whitespace() {
 3875                    chars.reverse();
 3876                    return Some(chars.iter().collect());
 3877                }
 3878                // If the previous character is not a whitespace, we are in the middle of a word
 3879                // and we only want to complete the shortcode if the word is made up of other emojis
 3880                let mut containing_word = String::new();
 3881                for ch in snapshot
 3882                    .reversed_chars_at(position)
 3883                    .skip(chars.len() + 1)
 3884                    .take(100)
 3885                {
 3886                    if ch.is_whitespace() {
 3887                        break;
 3888                    }
 3889                    containing_word.push(ch);
 3890                }
 3891                let containing_word = containing_word.chars().rev().collect::<String>();
 3892                if util::word_consists_of_emojis(containing_word.as_str()) {
 3893                    chars.reverse();
 3894                    return Some(chars.iter().collect());
 3895                }
 3896            }
 3897
 3898            if char.is_whitespace() || !char.is_ascii() {
 3899                return None;
 3900            }
 3901            if char == ':' {
 3902                found_colon = true;
 3903            } else {
 3904                chars.push(char);
 3905            }
 3906        }
 3907        // Found a possible emoji shortcode at the beginning of the buffer
 3908        chars.reverse();
 3909        Some(chars.iter().collect())
 3910    }
 3911
 3912    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 3913        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3914        self.transact(window, cx, |this, window, cx| {
 3915            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 3916                let selections = this.selections.all::<usize>(cx);
 3917                let multi_buffer = this.buffer.read(cx);
 3918                let buffer = multi_buffer.snapshot(cx);
 3919                selections
 3920                    .iter()
 3921                    .map(|selection| {
 3922                        let start_point = selection.start.to_point(&buffer);
 3923                        let mut existing_indent =
 3924                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 3925                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 3926                        let start = selection.start;
 3927                        let end = selection.end;
 3928                        let selection_is_empty = start == end;
 3929                        let language_scope = buffer.language_scope_at(start);
 3930                        let (
 3931                            comment_delimiter,
 3932                            doc_delimiter,
 3933                            insert_extra_newline,
 3934                            indent_on_newline,
 3935                            indent_on_extra_newline,
 3936                        ) = if let Some(language) = &language_scope {
 3937                            let mut insert_extra_newline =
 3938                                insert_extra_newline_brackets(&buffer, start..end, language)
 3939                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 3940
 3941                            // Comment extension on newline is allowed only for cursor selections
 3942                            let comment_delimiter = maybe!({
 3943                                if !selection_is_empty {
 3944                                    return None;
 3945                                }
 3946
 3947                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 3948                                    return None;
 3949                                }
 3950
 3951                                let delimiters = language.line_comment_prefixes();
 3952                                let max_len_of_delimiter =
 3953                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 3954                                let (snapshot, range) =
 3955                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 3956
 3957                                let mut index_of_first_non_whitespace = 0;
 3958                                let comment_candidate = snapshot
 3959                                    .chars_for_range(range)
 3960                                    .skip_while(|c| {
 3961                                        let should_skip = c.is_whitespace();
 3962                                        if should_skip {
 3963                                            index_of_first_non_whitespace += 1;
 3964                                        }
 3965                                        should_skip
 3966                                    })
 3967                                    .take(max_len_of_delimiter)
 3968                                    .collect::<String>();
 3969                                let comment_prefix = delimiters.iter().find(|comment_prefix| {
 3970                                    comment_candidate.starts_with(comment_prefix.as_ref())
 3971                                })?;
 3972                                let cursor_is_placed_after_comment_marker =
 3973                                    index_of_first_non_whitespace + comment_prefix.len()
 3974                                        <= start_point.column as usize;
 3975                                if cursor_is_placed_after_comment_marker {
 3976                                    Some(comment_prefix.clone())
 3977                                } else {
 3978                                    None
 3979                                }
 3980                            });
 3981
 3982                            let mut indent_on_newline = IndentSize::spaces(0);
 3983                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 3984
 3985                            let doc_delimiter = maybe!({
 3986                                if !selection_is_empty {
 3987                                    return None;
 3988                                }
 3989
 3990                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 3991                                    return None;
 3992                                }
 3993
 3994                                let DocumentationConfig {
 3995                                    start: start_tag,
 3996                                    end: end_tag,
 3997                                    prefix: delimiter,
 3998                                    tab_size: len,
 3999                                } = language.documentation()?;
 4000
 4001                                let (snapshot, range) =
 4002                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4003
 4004                                let num_of_whitespaces = snapshot
 4005                                    .chars_for_range(range.clone())
 4006                                    .take_while(|c| c.is_whitespace())
 4007                                    .count();
 4008
 4009                                let cursor_is_after_start_tag = {
 4010                                    let start_tag_len = start_tag.len();
 4011                                    let start_tag_line = snapshot
 4012                                        .chars_for_range(range.clone())
 4013                                        .skip(num_of_whitespaces)
 4014                                        .take(start_tag_len)
 4015                                        .collect::<String>();
 4016                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4017                                        num_of_whitespaces + start_tag_len
 4018                                            <= start_point.column as usize
 4019                                    } else {
 4020                                        false
 4021                                    }
 4022                                };
 4023
 4024                                let cursor_is_after_delimiter = {
 4025                                    let delimiter_trim = delimiter.trim_end();
 4026                                    let delimiter_line = snapshot
 4027                                        .chars_for_range(range.clone())
 4028                                        .skip(num_of_whitespaces)
 4029                                        .take(delimiter_trim.len())
 4030                                        .collect::<String>();
 4031                                    if delimiter_line.starts_with(delimiter_trim) {
 4032                                        num_of_whitespaces + delimiter_trim.len()
 4033                                            <= start_point.column as usize
 4034                                    } else {
 4035                                        false
 4036                                    }
 4037                                };
 4038
 4039                                let cursor_is_before_end_tag_if_exists = {
 4040                                    let num_of_whitespaces_rev = snapshot
 4041                                        .reversed_chars_for_range(range.clone())
 4042                                        .take_while(|c| c.is_whitespace())
 4043                                        .count();
 4044                                    let mut line_iter = snapshot
 4045                                        .reversed_chars_for_range(range)
 4046                                        .skip(num_of_whitespaces_rev);
 4047                                    let end_tag_exists = end_tag
 4048                                        .chars()
 4049                                        .rev()
 4050                                        .all(|char| line_iter.next() == Some(char));
 4051                                    if end_tag_exists {
 4052                                        let max_point = snapshot.line_len(start_point.row) as usize;
 4053                                        let ordering = (num_of_whitespaces_rev
 4054                                            + end_tag.len()
 4055                                            + start_point.column as usize)
 4056                                            .cmp(&max_point);
 4057                                        let cursor_is_before_end_tag =
 4058                                            ordering != Ordering::Greater;
 4059                                        if cursor_is_after_start_tag {
 4060                                            if cursor_is_before_end_tag {
 4061                                                insert_extra_newline = true;
 4062                                            }
 4063                                            let cursor_is_at_start_of_end_tag =
 4064                                                ordering == Ordering::Equal;
 4065                                            if cursor_is_at_start_of_end_tag {
 4066                                                indent_on_extra_newline.len = (*len).into();
 4067                                            }
 4068                                        }
 4069                                        cursor_is_before_end_tag
 4070                                    } else {
 4071                                        true
 4072                                    }
 4073                                };
 4074
 4075                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4076                                    && cursor_is_before_end_tag_if_exists
 4077                                {
 4078                                    if cursor_is_after_start_tag {
 4079                                        indent_on_newline.len = (*len).into();
 4080                                    }
 4081                                    Some(delimiter.clone())
 4082                                } else {
 4083                                    None
 4084                                }
 4085                            });
 4086
 4087                            (
 4088                                comment_delimiter,
 4089                                doc_delimiter,
 4090                                insert_extra_newline,
 4091                                indent_on_newline,
 4092                                indent_on_extra_newline,
 4093                            )
 4094                        } else {
 4095                            (
 4096                                None,
 4097                                None,
 4098                                false,
 4099                                IndentSize::default(),
 4100                                IndentSize::default(),
 4101                            )
 4102                        };
 4103
 4104                        let prevent_auto_indent = doc_delimiter.is_some();
 4105                        let delimiter = comment_delimiter.or(doc_delimiter);
 4106
 4107                        let capacity_for_delimiter =
 4108                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4109                        let mut new_text = String::with_capacity(
 4110                            1 + capacity_for_delimiter
 4111                                + existing_indent.len as usize
 4112                                + indent_on_newline.len as usize
 4113                                + indent_on_extra_newline.len as usize,
 4114                        );
 4115                        new_text.push('\n');
 4116                        new_text.extend(existing_indent.chars());
 4117                        new_text.extend(indent_on_newline.chars());
 4118
 4119                        if let Some(delimiter) = &delimiter {
 4120                            new_text.push_str(delimiter);
 4121                        }
 4122
 4123                        if insert_extra_newline {
 4124                            new_text.push('\n');
 4125                            new_text.extend(existing_indent.chars());
 4126                            new_text.extend(indent_on_extra_newline.chars());
 4127                        }
 4128
 4129                        let anchor = buffer.anchor_after(end);
 4130                        let new_selection = selection.map(|_| anchor);
 4131                        (
 4132                            ((start..end, new_text), prevent_auto_indent),
 4133                            (insert_extra_newline, new_selection),
 4134                        )
 4135                    })
 4136                    .unzip()
 4137            };
 4138
 4139            let mut auto_indent_edits = Vec::new();
 4140            let mut edits = Vec::new();
 4141            for (edit, prevent_auto_indent) in edits_with_flags {
 4142                if prevent_auto_indent {
 4143                    edits.push(edit);
 4144                } else {
 4145                    auto_indent_edits.push(edit);
 4146                }
 4147            }
 4148            if !edits.is_empty() {
 4149                this.edit(edits, cx);
 4150            }
 4151            if !auto_indent_edits.is_empty() {
 4152                this.edit_with_autoindent(auto_indent_edits, cx);
 4153            }
 4154
 4155            let buffer = this.buffer.read(cx).snapshot(cx);
 4156            let new_selections = selection_info
 4157                .into_iter()
 4158                .map(|(extra_newline_inserted, new_selection)| {
 4159                    let mut cursor = new_selection.end.to_point(&buffer);
 4160                    if extra_newline_inserted {
 4161                        cursor.row -= 1;
 4162                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4163                    }
 4164                    new_selection.map(|_| cursor)
 4165                })
 4166                .collect();
 4167
 4168            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4169                s.select(new_selections)
 4170            });
 4171            this.refresh_inline_completion(true, false, window, cx);
 4172        });
 4173    }
 4174
 4175    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4176        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4177
 4178        let buffer = self.buffer.read(cx);
 4179        let snapshot = buffer.snapshot(cx);
 4180
 4181        let mut edits = Vec::new();
 4182        let mut rows = Vec::new();
 4183
 4184        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4185            let cursor = selection.head();
 4186            let row = cursor.row;
 4187
 4188            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4189
 4190            let newline = "\n".to_string();
 4191            edits.push((start_of_line..start_of_line, newline));
 4192
 4193            rows.push(row + rows_inserted as u32);
 4194        }
 4195
 4196        self.transact(window, cx, |editor, window, cx| {
 4197            editor.edit(edits, cx);
 4198
 4199            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4200                let mut index = 0;
 4201                s.move_cursors_with(|map, _, _| {
 4202                    let row = rows[index];
 4203                    index += 1;
 4204
 4205                    let point = Point::new(row, 0);
 4206                    let boundary = map.next_line_boundary(point).1;
 4207                    let clipped = map.clip_point(boundary, Bias::Left);
 4208
 4209                    (clipped, SelectionGoal::None)
 4210                });
 4211            });
 4212
 4213            let mut indent_edits = Vec::new();
 4214            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4215            for row in rows {
 4216                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4217                for (row, indent) in indents {
 4218                    if indent.len == 0 {
 4219                        continue;
 4220                    }
 4221
 4222                    let text = match indent.kind {
 4223                        IndentKind::Space => " ".repeat(indent.len as usize),
 4224                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4225                    };
 4226                    let point = Point::new(row.0, 0);
 4227                    indent_edits.push((point..point, text));
 4228                }
 4229            }
 4230            editor.edit(indent_edits, cx);
 4231        });
 4232    }
 4233
 4234    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4235        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4236
 4237        let buffer = self.buffer.read(cx);
 4238        let snapshot = buffer.snapshot(cx);
 4239
 4240        let mut edits = Vec::new();
 4241        let mut rows = Vec::new();
 4242        let mut rows_inserted = 0;
 4243
 4244        for selection in self.selections.all_adjusted(cx) {
 4245            let cursor = selection.head();
 4246            let row = cursor.row;
 4247
 4248            let point = Point::new(row + 1, 0);
 4249            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4250
 4251            let newline = "\n".to_string();
 4252            edits.push((start_of_line..start_of_line, newline));
 4253
 4254            rows_inserted += 1;
 4255            rows.push(row + rows_inserted);
 4256        }
 4257
 4258        self.transact(window, cx, |editor, window, cx| {
 4259            editor.edit(edits, cx);
 4260
 4261            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4262                let mut index = 0;
 4263                s.move_cursors_with(|map, _, _| {
 4264                    let row = rows[index];
 4265                    index += 1;
 4266
 4267                    let point = Point::new(row, 0);
 4268                    let boundary = map.next_line_boundary(point).1;
 4269                    let clipped = map.clip_point(boundary, Bias::Left);
 4270
 4271                    (clipped, SelectionGoal::None)
 4272                });
 4273            });
 4274
 4275            let mut indent_edits = Vec::new();
 4276            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4277            for row in rows {
 4278                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4279                for (row, indent) in indents {
 4280                    if indent.len == 0 {
 4281                        continue;
 4282                    }
 4283
 4284                    let text = match indent.kind {
 4285                        IndentKind::Space => " ".repeat(indent.len as usize),
 4286                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4287                    };
 4288                    let point = Point::new(row.0, 0);
 4289                    indent_edits.push((point..point, text));
 4290                }
 4291            }
 4292            editor.edit(indent_edits, cx);
 4293        });
 4294    }
 4295
 4296    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4297        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4298            original_indent_columns: Vec::new(),
 4299        });
 4300        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4301    }
 4302
 4303    fn insert_with_autoindent_mode(
 4304        &mut self,
 4305        text: &str,
 4306        autoindent_mode: Option<AutoindentMode>,
 4307        window: &mut Window,
 4308        cx: &mut Context<Self>,
 4309    ) {
 4310        if self.read_only(cx) {
 4311            return;
 4312        }
 4313
 4314        let text: Arc<str> = text.into();
 4315        self.transact(window, cx, |this, window, cx| {
 4316            let old_selections = this.selections.all_adjusted(cx);
 4317            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4318                let anchors = {
 4319                    let snapshot = buffer.read(cx);
 4320                    old_selections
 4321                        .iter()
 4322                        .map(|s| {
 4323                            let anchor = snapshot.anchor_after(s.head());
 4324                            s.map(|_| anchor)
 4325                        })
 4326                        .collect::<Vec<_>>()
 4327                };
 4328                buffer.edit(
 4329                    old_selections
 4330                        .iter()
 4331                        .map(|s| (s.start..s.end, text.clone())),
 4332                    autoindent_mode,
 4333                    cx,
 4334                );
 4335                anchors
 4336            });
 4337
 4338            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4339                s.select_anchors(selection_anchors);
 4340            });
 4341
 4342            cx.notify();
 4343        });
 4344    }
 4345
 4346    fn trigger_completion_on_input(
 4347        &mut self,
 4348        text: &str,
 4349        trigger_in_words: bool,
 4350        window: &mut Window,
 4351        cx: &mut Context<Self>,
 4352    ) {
 4353        let ignore_completion_provider = self
 4354            .context_menu
 4355            .borrow()
 4356            .as_ref()
 4357            .map(|menu| match menu {
 4358                CodeContextMenu::Completions(completions_menu) => {
 4359                    completions_menu.ignore_completion_provider
 4360                }
 4361                CodeContextMenu::CodeActions(_) => false,
 4362            })
 4363            .unwrap_or(false);
 4364
 4365        if ignore_completion_provider {
 4366            self.show_word_completions(&ShowWordCompletions, window, cx);
 4367        } else if self.is_completion_trigger(text, trigger_in_words, cx) {
 4368            self.show_completions(
 4369                &ShowCompletions {
 4370                    trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4371                },
 4372                window,
 4373                cx,
 4374            );
 4375        } else {
 4376            self.hide_context_menu(window, cx);
 4377        }
 4378    }
 4379
 4380    fn is_completion_trigger(
 4381        &self,
 4382        text: &str,
 4383        trigger_in_words: bool,
 4384        cx: &mut Context<Self>,
 4385    ) -> bool {
 4386        let position = self.selections.newest_anchor().head();
 4387        let multibuffer = self.buffer.read(cx);
 4388        let Some(buffer) = position
 4389            .buffer_id
 4390            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4391        else {
 4392            return false;
 4393        };
 4394
 4395        if let Some(completion_provider) = &self.completion_provider {
 4396            completion_provider.is_completion_trigger(
 4397                &buffer,
 4398                position.text_anchor,
 4399                text,
 4400                trigger_in_words,
 4401                cx,
 4402            )
 4403        } else {
 4404            false
 4405        }
 4406    }
 4407
 4408    /// If any empty selections is touching the start of its innermost containing autoclose
 4409    /// region, expand it to select the brackets.
 4410    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4411        let selections = self.selections.all::<usize>(cx);
 4412        let buffer = self.buffer.read(cx).read(cx);
 4413        let new_selections = self
 4414            .selections_with_autoclose_regions(selections, &buffer)
 4415            .map(|(mut selection, region)| {
 4416                if !selection.is_empty() {
 4417                    return selection;
 4418                }
 4419
 4420                if let Some(region) = region {
 4421                    let mut range = region.range.to_offset(&buffer);
 4422                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4423                        range.start -= region.pair.start.len();
 4424                        if buffer.contains_str_at(range.start, &region.pair.start)
 4425                            && buffer.contains_str_at(range.end, &region.pair.end)
 4426                        {
 4427                            range.end += region.pair.end.len();
 4428                            selection.start = range.start;
 4429                            selection.end = range.end;
 4430
 4431                            return selection;
 4432                        }
 4433                    }
 4434                }
 4435
 4436                let always_treat_brackets_as_autoclosed = buffer
 4437                    .language_settings_at(selection.start, cx)
 4438                    .always_treat_brackets_as_autoclosed;
 4439
 4440                if !always_treat_brackets_as_autoclosed {
 4441                    return selection;
 4442                }
 4443
 4444                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4445                    for (pair, enabled) in scope.brackets() {
 4446                        if !enabled || !pair.close {
 4447                            continue;
 4448                        }
 4449
 4450                        if buffer.contains_str_at(selection.start, &pair.end) {
 4451                            let pair_start_len = pair.start.len();
 4452                            if buffer.contains_str_at(
 4453                                selection.start.saturating_sub(pair_start_len),
 4454                                &pair.start,
 4455                            ) {
 4456                                selection.start -= pair_start_len;
 4457                                selection.end += pair.end.len();
 4458
 4459                                return selection;
 4460                            }
 4461                        }
 4462                    }
 4463                }
 4464
 4465                selection
 4466            })
 4467            .collect();
 4468
 4469        drop(buffer);
 4470        self.change_selections(None, window, cx, |selections| {
 4471            selections.select(new_selections)
 4472        });
 4473    }
 4474
 4475    /// Iterate the given selections, and for each one, find the smallest surrounding
 4476    /// autoclose region. This uses the ordering of the selections and the autoclose
 4477    /// regions to avoid repeated comparisons.
 4478    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4479        &'a self,
 4480        selections: impl IntoIterator<Item = Selection<D>>,
 4481        buffer: &'a MultiBufferSnapshot,
 4482    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4483        let mut i = 0;
 4484        let mut regions = self.autoclose_regions.as_slice();
 4485        selections.into_iter().map(move |selection| {
 4486            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4487
 4488            let mut enclosing = None;
 4489            while let Some(pair_state) = regions.get(i) {
 4490                if pair_state.range.end.to_offset(buffer) < range.start {
 4491                    regions = &regions[i + 1..];
 4492                    i = 0;
 4493                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4494                    break;
 4495                } else {
 4496                    if pair_state.selection_id == selection.id {
 4497                        enclosing = Some(pair_state);
 4498                    }
 4499                    i += 1;
 4500                }
 4501            }
 4502
 4503            (selection, enclosing)
 4504        })
 4505    }
 4506
 4507    /// Remove any autoclose regions that no longer contain their selection.
 4508    fn invalidate_autoclose_regions(
 4509        &mut self,
 4510        mut selections: &[Selection<Anchor>],
 4511        buffer: &MultiBufferSnapshot,
 4512    ) {
 4513        self.autoclose_regions.retain(|state| {
 4514            let mut i = 0;
 4515            while let Some(selection) = selections.get(i) {
 4516                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4517                    selections = &selections[1..];
 4518                    continue;
 4519                }
 4520                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4521                    break;
 4522                }
 4523                if selection.id == state.selection_id {
 4524                    return true;
 4525                } else {
 4526                    i += 1;
 4527                }
 4528            }
 4529            false
 4530        });
 4531    }
 4532
 4533    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4534        let offset = position.to_offset(buffer);
 4535        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4536        if offset > word_range.start && kind == Some(CharKind::Word) {
 4537            Some(
 4538                buffer
 4539                    .text_for_range(word_range.start..offset)
 4540                    .collect::<String>(),
 4541            )
 4542        } else {
 4543            None
 4544        }
 4545    }
 4546
 4547    pub fn toggle_inline_values(
 4548        &mut self,
 4549        _: &ToggleInlineValues,
 4550        _: &mut Window,
 4551        cx: &mut Context<Self>,
 4552    ) {
 4553        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4554
 4555        self.refresh_inline_values(cx);
 4556    }
 4557
 4558    pub fn toggle_inlay_hints(
 4559        &mut self,
 4560        _: &ToggleInlayHints,
 4561        _: &mut Window,
 4562        cx: &mut Context<Self>,
 4563    ) {
 4564        self.refresh_inlay_hints(
 4565            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4566            cx,
 4567        );
 4568    }
 4569
 4570    pub fn inlay_hints_enabled(&self) -> bool {
 4571        self.inlay_hint_cache.enabled
 4572    }
 4573
 4574    pub fn inline_values_enabled(&self) -> bool {
 4575        self.inline_value_cache.enabled
 4576    }
 4577
 4578    #[cfg(any(test, feature = "test-support"))]
 4579    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4580        self.display_map
 4581            .read(cx)
 4582            .current_inlays()
 4583            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4584            .cloned()
 4585            .collect()
 4586    }
 4587
 4588    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4589        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4590            return;
 4591        }
 4592
 4593        let reason_description = reason.description();
 4594        let ignore_debounce = matches!(
 4595            reason,
 4596            InlayHintRefreshReason::SettingsChange(_)
 4597                | InlayHintRefreshReason::Toggle(_)
 4598                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4599                | InlayHintRefreshReason::ModifiersChanged(_)
 4600        );
 4601        let (invalidate_cache, required_languages) = match reason {
 4602            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4603                match self.inlay_hint_cache.modifiers_override(enabled) {
 4604                    Some(enabled) => {
 4605                        if enabled {
 4606                            (InvalidationStrategy::RefreshRequested, None)
 4607                        } else {
 4608                            self.splice_inlays(
 4609                                &self
 4610                                    .visible_inlay_hints(cx)
 4611                                    .iter()
 4612                                    .map(|inlay| inlay.id)
 4613                                    .collect::<Vec<InlayId>>(),
 4614                                Vec::new(),
 4615                                cx,
 4616                            );
 4617                            return;
 4618                        }
 4619                    }
 4620                    None => return,
 4621                }
 4622            }
 4623            InlayHintRefreshReason::Toggle(enabled) => {
 4624                if self.inlay_hint_cache.toggle(enabled) {
 4625                    if enabled {
 4626                        (InvalidationStrategy::RefreshRequested, None)
 4627                    } else {
 4628                        self.splice_inlays(
 4629                            &self
 4630                                .visible_inlay_hints(cx)
 4631                                .iter()
 4632                                .map(|inlay| inlay.id)
 4633                                .collect::<Vec<InlayId>>(),
 4634                            Vec::new(),
 4635                            cx,
 4636                        );
 4637                        return;
 4638                    }
 4639                } else {
 4640                    return;
 4641                }
 4642            }
 4643            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4644                match self.inlay_hint_cache.update_settings(
 4645                    &self.buffer,
 4646                    new_settings,
 4647                    self.visible_inlay_hints(cx),
 4648                    cx,
 4649                ) {
 4650                    ControlFlow::Break(Some(InlaySplice {
 4651                        to_remove,
 4652                        to_insert,
 4653                    })) => {
 4654                        self.splice_inlays(&to_remove, to_insert, cx);
 4655                        return;
 4656                    }
 4657                    ControlFlow::Break(None) => return,
 4658                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4659                }
 4660            }
 4661            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4662                if let Some(InlaySplice {
 4663                    to_remove,
 4664                    to_insert,
 4665                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4666                {
 4667                    self.splice_inlays(&to_remove, to_insert, cx);
 4668                }
 4669                self.display_map.update(cx, |display_map, _| {
 4670                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4671                });
 4672                return;
 4673            }
 4674            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4675            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4676                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4677            }
 4678            InlayHintRefreshReason::RefreshRequested => {
 4679                (InvalidationStrategy::RefreshRequested, None)
 4680            }
 4681        };
 4682
 4683        if let Some(InlaySplice {
 4684            to_remove,
 4685            to_insert,
 4686        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4687            reason_description,
 4688            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4689            invalidate_cache,
 4690            ignore_debounce,
 4691            cx,
 4692        ) {
 4693            self.splice_inlays(&to_remove, to_insert, cx);
 4694        }
 4695    }
 4696
 4697    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4698        self.display_map
 4699            .read(cx)
 4700            .current_inlays()
 4701            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4702            .cloned()
 4703            .collect()
 4704    }
 4705
 4706    pub fn excerpts_for_inlay_hints_query(
 4707        &self,
 4708        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4709        cx: &mut Context<Editor>,
 4710    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4711        let Some(project) = self.project.as_ref() else {
 4712            return HashMap::default();
 4713        };
 4714        let project = project.read(cx);
 4715        let multi_buffer = self.buffer().read(cx);
 4716        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4717        let multi_buffer_visible_start = self
 4718            .scroll_manager
 4719            .anchor()
 4720            .anchor
 4721            .to_point(&multi_buffer_snapshot);
 4722        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4723            multi_buffer_visible_start
 4724                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4725            Bias::Left,
 4726        );
 4727        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4728        multi_buffer_snapshot
 4729            .range_to_buffer_ranges(multi_buffer_visible_range)
 4730            .into_iter()
 4731            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4732            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4733                let buffer_file = project::File::from_dyn(buffer.file())?;
 4734                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4735                let worktree_entry = buffer_worktree
 4736                    .read(cx)
 4737                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4738                if worktree_entry.is_ignored {
 4739                    return None;
 4740                }
 4741
 4742                let language = buffer.language()?;
 4743                if let Some(restrict_to_languages) = restrict_to_languages {
 4744                    if !restrict_to_languages.contains(language) {
 4745                        return None;
 4746                    }
 4747                }
 4748                Some((
 4749                    excerpt_id,
 4750                    (
 4751                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4752                        buffer.version().clone(),
 4753                        excerpt_visible_range,
 4754                    ),
 4755                ))
 4756            })
 4757            .collect()
 4758    }
 4759
 4760    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4761        TextLayoutDetails {
 4762            text_system: window.text_system().clone(),
 4763            editor_style: self.style.clone().unwrap(),
 4764            rem_size: window.rem_size(),
 4765            scroll_anchor: self.scroll_manager.anchor(),
 4766            visible_rows: self.visible_line_count(),
 4767            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4768        }
 4769    }
 4770
 4771    pub fn splice_inlays(
 4772        &self,
 4773        to_remove: &[InlayId],
 4774        to_insert: Vec<Inlay>,
 4775        cx: &mut Context<Self>,
 4776    ) {
 4777        self.display_map.update(cx, |display_map, cx| {
 4778            display_map.splice_inlays(to_remove, to_insert, cx)
 4779        });
 4780        cx.notify();
 4781    }
 4782
 4783    fn trigger_on_type_formatting(
 4784        &self,
 4785        input: String,
 4786        window: &mut Window,
 4787        cx: &mut Context<Self>,
 4788    ) -> Option<Task<Result<()>>> {
 4789        if input.len() != 1 {
 4790            return None;
 4791        }
 4792
 4793        let project = self.project.as_ref()?;
 4794        let position = self.selections.newest_anchor().head();
 4795        let (buffer, buffer_position) = self
 4796            .buffer
 4797            .read(cx)
 4798            .text_anchor_for_position(position, cx)?;
 4799
 4800        let settings = language_settings::language_settings(
 4801            buffer
 4802                .read(cx)
 4803                .language_at(buffer_position)
 4804                .map(|l| l.name()),
 4805            buffer.read(cx).file(),
 4806            cx,
 4807        );
 4808        if !settings.use_on_type_format {
 4809            return None;
 4810        }
 4811
 4812        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 4813        // hence we do LSP request & edit on host side only — add formats to host's history.
 4814        let push_to_lsp_host_history = true;
 4815        // If this is not the host, append its history with new edits.
 4816        let push_to_client_history = project.read(cx).is_via_collab();
 4817
 4818        let on_type_formatting = project.update(cx, |project, cx| {
 4819            project.on_type_format(
 4820                buffer.clone(),
 4821                buffer_position,
 4822                input,
 4823                push_to_lsp_host_history,
 4824                cx,
 4825            )
 4826        });
 4827        Some(cx.spawn_in(window, async move |editor, cx| {
 4828            if let Some(transaction) = on_type_formatting.await? {
 4829                if push_to_client_history {
 4830                    buffer
 4831                        .update(cx, |buffer, _| {
 4832                            buffer.push_transaction(transaction, Instant::now());
 4833                            buffer.finalize_last_transaction();
 4834                        })
 4835                        .ok();
 4836                }
 4837                editor.update(cx, |editor, cx| {
 4838                    editor.refresh_document_highlights(cx);
 4839                })?;
 4840            }
 4841            Ok(())
 4842        }))
 4843    }
 4844
 4845    pub fn show_word_completions(
 4846        &mut self,
 4847        _: &ShowWordCompletions,
 4848        window: &mut Window,
 4849        cx: &mut Context<Self>,
 4850    ) {
 4851        self.open_completions_menu(true, None, window, cx);
 4852    }
 4853
 4854    pub fn show_completions(
 4855        &mut self,
 4856        options: &ShowCompletions,
 4857        window: &mut Window,
 4858        cx: &mut Context<Self>,
 4859    ) {
 4860        self.open_completions_menu(false, options.trigger.as_deref(), window, cx);
 4861    }
 4862
 4863    fn open_completions_menu(
 4864        &mut self,
 4865        ignore_completion_provider: bool,
 4866        trigger: Option<&str>,
 4867        window: &mut Window,
 4868        cx: &mut Context<Self>,
 4869    ) {
 4870        if self.pending_rename.is_some() {
 4871            return;
 4872        }
 4873        if !self.snippet_stack.is_empty() && self.context_menu.borrow().as_ref().is_some() {
 4874            return;
 4875        }
 4876
 4877        let position = self.selections.newest_anchor().head();
 4878        if position.diff_base_anchor.is_some() {
 4879            return;
 4880        }
 4881        let (buffer, buffer_position) =
 4882            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 4883                output
 4884            } else {
 4885                return;
 4886            };
 4887        let buffer_snapshot = buffer.read(cx).snapshot();
 4888        let show_completion_documentation = buffer_snapshot
 4889            .settings_at(buffer_position, cx)
 4890            .show_completion_documentation;
 4891
 4892        let query = Self::completion_query(&self.buffer.read(cx).read(cx), position);
 4893
 4894        let trigger_kind = match trigger {
 4895            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 4896                CompletionTriggerKind::TRIGGER_CHARACTER
 4897            }
 4898            _ => CompletionTriggerKind::INVOKED,
 4899        };
 4900        let completion_context = CompletionContext {
 4901            trigger_character: trigger.and_then(|trigger| {
 4902                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 4903                    Some(String::from(trigger))
 4904                } else {
 4905                    None
 4906                }
 4907            }),
 4908            trigger_kind,
 4909        };
 4910
 4911        let (old_range, word_kind) = buffer_snapshot.surrounding_word(buffer_position);
 4912        let (old_range, word_to_exclude) = if word_kind == Some(CharKind::Word) {
 4913            let word_to_exclude = buffer_snapshot
 4914                .text_for_range(old_range.clone())
 4915                .collect::<String>();
 4916            (
 4917                buffer_snapshot.anchor_before(old_range.start)
 4918                    ..buffer_snapshot.anchor_after(old_range.end),
 4919                Some(word_to_exclude),
 4920            )
 4921        } else {
 4922            (buffer_position..buffer_position, None)
 4923        };
 4924
 4925        let completion_settings = language_settings(
 4926            buffer_snapshot
 4927                .language_at(buffer_position)
 4928                .map(|language| language.name()),
 4929            buffer_snapshot.file(),
 4930            cx,
 4931        )
 4932        .completions;
 4933
 4934        // The document can be large, so stay in reasonable bounds when searching for words,
 4935        // otherwise completion pop-up might be slow to appear.
 4936        const WORD_LOOKUP_ROWS: u32 = 5_000;
 4937        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 4938        let min_word_search = buffer_snapshot.clip_point(
 4939            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 4940            Bias::Left,
 4941        );
 4942        let max_word_search = buffer_snapshot.clip_point(
 4943            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 4944            Bias::Right,
 4945        );
 4946        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 4947            ..buffer_snapshot.point_to_offset(max_word_search);
 4948
 4949        let provider = self
 4950            .completion_provider
 4951            .as_ref()
 4952            .filter(|_| !ignore_completion_provider);
 4953        let skip_digits = query
 4954            .as_ref()
 4955            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 4956
 4957        let (mut words, provided_completions) = match provider {
 4958            Some(provider) => {
 4959                let completions = provider.completions(
 4960                    position.excerpt_id,
 4961                    &buffer,
 4962                    buffer_position,
 4963                    completion_context,
 4964                    window,
 4965                    cx,
 4966                );
 4967
 4968                let words = match completion_settings.words {
 4969                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 4970                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 4971                        .background_spawn(async move {
 4972                            buffer_snapshot.words_in_range(WordsQuery {
 4973                                fuzzy_contents: None,
 4974                                range: word_search_range,
 4975                                skip_digits,
 4976                            })
 4977                        }),
 4978                };
 4979
 4980                (words, completions)
 4981            }
 4982            None => (
 4983                cx.background_spawn(async move {
 4984                    buffer_snapshot.words_in_range(WordsQuery {
 4985                        fuzzy_contents: None,
 4986                        range: word_search_range,
 4987                        skip_digits,
 4988                    })
 4989                }),
 4990                Task::ready(Ok(None)),
 4991            ),
 4992        };
 4993
 4994        let sort_completions = provider
 4995            .as_ref()
 4996            .map_or(false, |provider| provider.sort_completions());
 4997
 4998        let filter_completions = provider
 4999            .as_ref()
 5000            .map_or(true, |provider| provider.filter_completions());
 5001
 5002        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5003
 5004        let id = post_inc(&mut self.next_completion_id);
 5005        let task = cx.spawn_in(window, async move |editor, cx| {
 5006            async move {
 5007                editor.update(cx, |this, _| {
 5008                    this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5009                })?;
 5010
 5011                let mut completions = Vec::new();
 5012                if let Some(provided_completions) = provided_completions.await.log_err().flatten() {
 5013                    completions.extend(provided_completions);
 5014                    if completion_settings.words == WordsCompletionMode::Fallback {
 5015                        words = Task::ready(BTreeMap::default());
 5016                    }
 5017                }
 5018
 5019                let mut words = words.await;
 5020                if let Some(word_to_exclude) = &word_to_exclude {
 5021                    words.remove(word_to_exclude);
 5022                }
 5023                for lsp_completion in &completions {
 5024                    words.remove(&lsp_completion.new_text);
 5025                }
 5026                completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5027                    replace_range: old_range.clone(),
 5028                    new_text: word.clone(),
 5029                    label: CodeLabel::plain(word, None),
 5030                    icon_path: None,
 5031                    documentation: None,
 5032                    source: CompletionSource::BufferWord {
 5033                        word_range,
 5034                        resolved: false,
 5035                    },
 5036                    insert_text_mode: Some(InsertTextMode::AS_IS),
 5037                    confirm: None,
 5038                }));
 5039
 5040                let menu = if completions.is_empty() {
 5041                    None
 5042                } else {
 5043                    let mut menu = CompletionsMenu::new(
 5044                        id,
 5045                        sort_completions,
 5046                        show_completion_documentation,
 5047                        ignore_completion_provider,
 5048                        position,
 5049                        buffer.clone(),
 5050                        completions.into(),
 5051                        snippet_sort_order,
 5052                    );
 5053
 5054                    menu.filter(
 5055                        if filter_completions {
 5056                            query.as_deref()
 5057                        } else {
 5058                            None
 5059                        },
 5060                        cx.background_executor().clone(),
 5061                    )
 5062                    .await;
 5063
 5064                    menu.visible().then_some(menu)
 5065                };
 5066
 5067                editor.update_in(cx, |editor, window, cx| {
 5068                    match editor.context_menu.borrow().as_ref() {
 5069                        None => {}
 5070                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5071                            if prev_menu.id > id {
 5072                                return;
 5073                            }
 5074                        }
 5075                        _ => return,
 5076                    }
 5077
 5078                    if editor.focus_handle.is_focused(window) && menu.is_some() {
 5079                        let mut menu = menu.unwrap();
 5080                        menu.resolve_visible_completions(editor.completion_provider.as_deref(), cx);
 5081
 5082                        *editor.context_menu.borrow_mut() =
 5083                            Some(CodeContextMenu::Completions(menu));
 5084
 5085                        if editor.show_edit_predictions_in_menu() {
 5086                            editor.update_visible_inline_completion(window, cx);
 5087                        } else {
 5088                            editor.discard_inline_completion(false, cx);
 5089                        }
 5090
 5091                        cx.notify();
 5092                    } else if editor.completion_tasks.len() <= 1 {
 5093                        // If there are no more completion tasks and the last menu was
 5094                        // empty, we should hide it.
 5095                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5096                        // If it was already hidden and we don't show inline
 5097                        // completions in the menu, we should also show the
 5098                        // inline-completion when available.
 5099                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5100                            editor.update_visible_inline_completion(window, cx);
 5101                        }
 5102                    }
 5103                })?;
 5104
 5105                anyhow::Ok(())
 5106            }
 5107            .log_err()
 5108            .await
 5109        });
 5110
 5111        self.completion_tasks.push((id, task));
 5112    }
 5113
 5114    #[cfg(feature = "test-support")]
 5115    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5116        let menu = self.context_menu.borrow();
 5117        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5118            let completions = menu.completions.borrow();
 5119            Some(completions.to_vec())
 5120        } else {
 5121            None
 5122        }
 5123    }
 5124
 5125    pub fn confirm_completion(
 5126        &mut self,
 5127        action: &ConfirmCompletion,
 5128        window: &mut Window,
 5129        cx: &mut Context<Self>,
 5130    ) -> Option<Task<Result<()>>> {
 5131        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5132        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5133    }
 5134
 5135    pub fn confirm_completion_insert(
 5136        &mut self,
 5137        _: &ConfirmCompletionInsert,
 5138        window: &mut Window,
 5139        cx: &mut Context<Self>,
 5140    ) -> Option<Task<Result<()>>> {
 5141        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5142        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5143    }
 5144
 5145    pub fn confirm_completion_replace(
 5146        &mut self,
 5147        _: &ConfirmCompletionReplace,
 5148        window: &mut Window,
 5149        cx: &mut Context<Self>,
 5150    ) -> Option<Task<Result<()>>> {
 5151        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5152        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5153    }
 5154
 5155    pub fn compose_completion(
 5156        &mut self,
 5157        action: &ComposeCompletion,
 5158        window: &mut Window,
 5159        cx: &mut Context<Self>,
 5160    ) -> Option<Task<Result<()>>> {
 5161        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5162        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5163    }
 5164
 5165    fn do_completion(
 5166        &mut self,
 5167        item_ix: Option<usize>,
 5168        intent: CompletionIntent,
 5169        window: &mut Window,
 5170        cx: &mut Context<Editor>,
 5171    ) -> Option<Task<Result<()>>> {
 5172        use language::ToOffset as _;
 5173
 5174        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5175        else {
 5176            return None;
 5177        };
 5178
 5179        let candidate_id = {
 5180            let entries = completions_menu.entries.borrow();
 5181            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5182            if self.show_edit_predictions_in_menu() {
 5183                self.discard_inline_completion(true, cx);
 5184            }
 5185            mat.candidate_id
 5186        };
 5187
 5188        let buffer_handle = completions_menu.buffer;
 5189        let completion = completions_menu
 5190            .completions
 5191            .borrow()
 5192            .get(candidate_id)?
 5193            .clone();
 5194        cx.stop_propagation();
 5195
 5196        let snapshot = self.buffer.read(cx).snapshot(cx);
 5197        let newest_anchor = self.selections.newest_anchor();
 5198
 5199        let snippet;
 5200        let new_text;
 5201        if completion.is_snippet() {
 5202            let mut snippet_source = completion.new_text.clone();
 5203            if let Some(scope) = snapshot.language_scope_at(newest_anchor.head()) {
 5204                if scope.prefers_label_for_snippet_in_completion() {
 5205                    if let Some(label) = completion.label() {
 5206                        if matches!(
 5207                            completion.kind(),
 5208                            Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
 5209                        ) {
 5210                            snippet_source = label;
 5211                        }
 5212                    }
 5213                }
 5214            }
 5215            snippet = Some(Snippet::parse(&snippet_source).log_err()?);
 5216            new_text = snippet.as_ref().unwrap().text.clone();
 5217        } else {
 5218            snippet = None;
 5219            new_text = completion.new_text.clone();
 5220        };
 5221
 5222        let replace_range = choose_completion_range(&completion, intent, &buffer_handle, cx);
 5223        let buffer = buffer_handle.read(cx);
 5224        let replace_range_multibuffer = {
 5225            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5226            let multibuffer_anchor = snapshot
 5227                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5228                .unwrap()
 5229                ..snapshot
 5230                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5231                    .unwrap();
 5232            multibuffer_anchor.start.to_offset(&snapshot)
 5233                ..multibuffer_anchor.end.to_offset(&snapshot)
 5234        };
 5235        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5236            return None;
 5237        }
 5238
 5239        let old_text = buffer
 5240            .text_for_range(replace_range.clone())
 5241            .collect::<String>();
 5242        let lookbehind = newest_anchor
 5243            .start
 5244            .text_anchor
 5245            .to_offset(buffer)
 5246            .saturating_sub(replace_range.start);
 5247        let lookahead = replace_range
 5248            .end
 5249            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5250        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5251        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5252
 5253        let selections = self.selections.all::<usize>(cx);
 5254        let mut ranges = Vec::new();
 5255        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5256
 5257        for selection in &selections {
 5258            let range = if selection.id == newest_anchor.id {
 5259                replace_range_multibuffer.clone()
 5260            } else {
 5261                let mut range = selection.range();
 5262
 5263                // if prefix is present, don't duplicate it
 5264                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5265                    range.start = range.start.saturating_sub(lookbehind);
 5266
 5267                    // if suffix is also present, mimic the newest cursor and replace it
 5268                    if selection.id != newest_anchor.id
 5269                        && snapshot.contains_str_at(range.end, suffix)
 5270                    {
 5271                        range.end += lookahead;
 5272                    }
 5273                }
 5274                range
 5275            };
 5276
 5277            ranges.push(range.clone());
 5278
 5279            if !self.linked_edit_ranges.is_empty() {
 5280                let start_anchor = snapshot.anchor_before(range.start);
 5281                let end_anchor = snapshot.anchor_after(range.end);
 5282                if let Some(ranges) = self
 5283                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5284                {
 5285                    for (buffer, edits) in ranges {
 5286                        linked_edits
 5287                            .entry(buffer.clone())
 5288                            .or_default()
 5289                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5290                    }
 5291                }
 5292            }
 5293        }
 5294
 5295        cx.emit(EditorEvent::InputHandled {
 5296            utf16_range_to_replace: None,
 5297            text: new_text.clone().into(),
 5298        });
 5299
 5300        self.transact(window, cx, |this, window, cx| {
 5301            if let Some(mut snippet) = snippet {
 5302                snippet.text = new_text.to_string();
 5303                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5304            } else {
 5305                this.buffer.update(cx, |buffer, cx| {
 5306                    let auto_indent = match completion.insert_text_mode {
 5307                        Some(InsertTextMode::AS_IS) => None,
 5308                        _ => this.autoindent_mode.clone(),
 5309                    };
 5310                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5311                    buffer.edit(edits, auto_indent, cx);
 5312                });
 5313            }
 5314            for (buffer, edits) in linked_edits {
 5315                buffer.update(cx, |buffer, cx| {
 5316                    let snapshot = buffer.snapshot();
 5317                    let edits = edits
 5318                        .into_iter()
 5319                        .map(|(range, text)| {
 5320                            use text::ToPoint as TP;
 5321                            let end_point = TP::to_point(&range.end, &snapshot);
 5322                            let start_point = TP::to_point(&range.start, &snapshot);
 5323                            (start_point..end_point, text)
 5324                        })
 5325                        .sorted_by_key(|(range, _)| range.start);
 5326                    buffer.edit(edits, None, cx);
 5327                })
 5328            }
 5329
 5330            this.refresh_inline_completion(true, false, window, cx);
 5331        });
 5332
 5333        let show_new_completions_on_confirm = completion
 5334            .confirm
 5335            .as_ref()
 5336            .map_or(false, |confirm| confirm(intent, window, cx));
 5337        if show_new_completions_on_confirm {
 5338            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5339        }
 5340
 5341        let provider = self.completion_provider.as_ref()?;
 5342        drop(completion);
 5343        let apply_edits = provider.apply_additional_edits_for_completion(
 5344            buffer_handle,
 5345            completions_menu.completions.clone(),
 5346            candidate_id,
 5347            true,
 5348            cx,
 5349        );
 5350
 5351        let editor_settings = EditorSettings::get_global(cx);
 5352        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5353            // After the code completion is finished, users often want to know what signatures are needed.
 5354            // so we should automatically call signature_help
 5355            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5356        }
 5357
 5358        Some(cx.foreground_executor().spawn(async move {
 5359            apply_edits.await?;
 5360            Ok(())
 5361        }))
 5362    }
 5363
 5364    pub fn toggle_code_actions(
 5365        &mut self,
 5366        action: &ToggleCodeActions,
 5367        window: &mut Window,
 5368        cx: &mut Context<Self>,
 5369    ) {
 5370        let quick_launch = action.quick_launch;
 5371        let mut context_menu = self.context_menu.borrow_mut();
 5372        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5373            if code_actions.deployed_from_indicator == action.deployed_from_indicator {
 5374                // Toggle if we're selecting the same one
 5375                *context_menu = None;
 5376                cx.notify();
 5377                return;
 5378            } else {
 5379                // Otherwise, clear it and start a new one
 5380                *context_menu = None;
 5381                cx.notify();
 5382            }
 5383        }
 5384        drop(context_menu);
 5385        let snapshot = self.snapshot(window, cx);
 5386        let deployed_from_indicator = action.deployed_from_indicator;
 5387        let mut task = self.code_actions_task.take();
 5388        let action = action.clone();
 5389        cx.spawn_in(window, async move |editor, cx| {
 5390            while let Some(prev_task) = task {
 5391                prev_task.await.log_err();
 5392                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
 5393            }
 5394
 5395            let spawned_test_task = editor.update_in(cx, |editor, window, cx| {
 5396                if editor.focus_handle.is_focused(window) {
 5397                    let multibuffer_point = action
 5398                        .deployed_from_indicator
 5399                        .map(|row| DisplayPoint::new(row, 0).to_point(&snapshot))
 5400                        .unwrap_or_else(|| editor.selections.newest::<Point>(cx).head());
 5401                    let (buffer, buffer_row) = snapshot
 5402                        .buffer_snapshot
 5403                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5404                        .and_then(|(buffer_snapshot, range)| {
 5405                            editor
 5406                                .buffer
 5407                                .read(cx)
 5408                                .buffer(buffer_snapshot.remote_id())
 5409                                .map(|buffer| (buffer, range.start.row))
 5410                        })?;
 5411                    let (_, code_actions) = editor
 5412                        .available_code_actions
 5413                        .clone()
 5414                        .and_then(|(location, code_actions)| {
 5415                            let snapshot = location.buffer.read(cx).snapshot();
 5416                            let point_range = location.range.to_point(&snapshot);
 5417                            let point_range = point_range.start.row..=point_range.end.row;
 5418                            if point_range.contains(&buffer_row) {
 5419                                Some((location, code_actions))
 5420                            } else {
 5421                                None
 5422                            }
 5423                        })
 5424                        .unzip();
 5425                    let buffer_id = buffer.read(cx).remote_id();
 5426                    let tasks = editor
 5427                        .tasks
 5428                        .get(&(buffer_id, buffer_row))
 5429                        .map(|t| Arc::new(t.to_owned()));
 5430                    if tasks.is_none() && code_actions.is_none() {
 5431                        return None;
 5432                    }
 5433
 5434                    editor.completion_tasks.clear();
 5435                    editor.discard_inline_completion(false, cx);
 5436                    let task_context =
 5437                        tasks
 5438                            .as_ref()
 5439                            .zip(editor.project.clone())
 5440                            .map(|(tasks, project)| {
 5441                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 5442                            });
 5443
 5444                    Some(cx.spawn_in(window, async move |editor, cx| {
 5445                        let task_context = match task_context {
 5446                            Some(task_context) => task_context.await,
 5447                            None => None,
 5448                        };
 5449                        let resolved_tasks =
 5450                            tasks
 5451                                .zip(task_context.clone())
 5452                                .map(|(tasks, task_context)| ResolvedTasks {
 5453                                    templates: tasks.resolve(&task_context).collect(),
 5454                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5455                                        multibuffer_point.row,
 5456                                        tasks.column,
 5457                                    )),
 5458                                });
 5459                        let debug_scenarios = editor.update(cx, |editor, cx| {
 5460                            if cx.has_flag::<DebuggerFeatureFlag>() {
 5461                                maybe!({
 5462                                    let project = editor.project.as_ref()?;
 5463                                    let dap_store = project.read(cx).dap_store();
 5464                                    let mut scenarios = vec![];
 5465                                    let resolved_tasks = resolved_tasks.as_ref()?;
 5466                                    let buffer = buffer.read(cx);
 5467                                    let language = buffer.language()?;
 5468                                    let file = buffer.file();
 5469                                    let debug_adapter =
 5470                                        language_settings(language.name().into(), file, cx)
 5471                                            .debuggers
 5472                                            .first()
 5473                                            .map(SharedString::from)
 5474                                            .or_else(|| {
 5475                                                language
 5476                                                    .config()
 5477                                                    .debuggers
 5478                                                    .first()
 5479                                                    .map(SharedString::from)
 5480                                            })?;
 5481
 5482                                    dap_store.update(cx, |dap_store, cx| {
 5483                                        for (_, task) in &resolved_tasks.templates {
 5484                                            if let Some(scenario) = dap_store
 5485                                                .debug_scenario_for_build_task(
 5486                                                    task.original_task().clone(),
 5487                                                    debug_adapter.clone().into(),
 5488                                                    task.display_label().to_owned().into(),
 5489                                                    cx,
 5490                                                )
 5491                                            {
 5492                                                scenarios.push(scenario);
 5493                                            }
 5494                                        }
 5495                                    });
 5496                                    Some(scenarios)
 5497                                })
 5498                                .unwrap_or_default()
 5499                            } else {
 5500                                vec![]
 5501                            }
 5502                        })?;
 5503                        let spawn_straight_away = quick_launch
 5504                            && resolved_tasks
 5505                                .as_ref()
 5506                                .map_or(false, |tasks| tasks.templates.len() == 1)
 5507                            && code_actions
 5508                                .as_ref()
 5509                                .map_or(true, |actions| actions.is_empty())
 5510                            && debug_scenarios.is_empty();
 5511                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
 5512                            *editor.context_menu.borrow_mut() =
 5513                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5514                                    buffer,
 5515                                    actions: CodeActionContents::new(
 5516                                        resolved_tasks,
 5517                                        code_actions,
 5518                                        debug_scenarios,
 5519                                        task_context.unwrap_or_default(),
 5520                                    ),
 5521                                    selected_item: Default::default(),
 5522                                    scroll_handle: UniformListScrollHandle::default(),
 5523                                    deployed_from_indicator,
 5524                                }));
 5525                            if spawn_straight_away {
 5526                                if let Some(task) = editor.confirm_code_action(
 5527                                    &ConfirmCodeAction { item_ix: Some(0) },
 5528                                    window,
 5529                                    cx,
 5530                                ) {
 5531                                    cx.notify();
 5532                                    return task;
 5533                                }
 5534                            }
 5535                            cx.notify();
 5536                            Task::ready(Ok(()))
 5537                        }) {
 5538                            task.await
 5539                        } else {
 5540                            Ok(())
 5541                        }
 5542                    }))
 5543                } else {
 5544                    Some(Task::ready(Ok(())))
 5545                }
 5546            })?;
 5547            if let Some(task) = spawned_test_task {
 5548                task.await?;
 5549            }
 5550
 5551            Ok::<_, anyhow::Error>(())
 5552        })
 5553        .detach_and_log_err(cx);
 5554    }
 5555
 5556    pub fn confirm_code_action(
 5557        &mut self,
 5558        action: &ConfirmCodeAction,
 5559        window: &mut Window,
 5560        cx: &mut Context<Self>,
 5561    ) -> Option<Task<Result<()>>> {
 5562        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5563
 5564        let actions_menu =
 5565            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5566                menu
 5567            } else {
 5568                return None;
 5569            };
 5570
 5571        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5572        let action = actions_menu.actions.get(action_ix)?;
 5573        let title = action.label();
 5574        let buffer = actions_menu.buffer;
 5575        let workspace = self.workspace()?;
 5576
 5577        match action {
 5578            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5579                workspace.update(cx, |workspace, cx| {
 5580                    workspace.schedule_resolved_task(
 5581                        task_source_kind,
 5582                        resolved_task,
 5583                        false,
 5584                        window,
 5585                        cx,
 5586                    );
 5587
 5588                    Some(Task::ready(Ok(())))
 5589                })
 5590            }
 5591            CodeActionsItem::CodeAction {
 5592                excerpt_id,
 5593                action,
 5594                provider,
 5595            } => {
 5596                let apply_code_action =
 5597                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5598                let workspace = workspace.downgrade();
 5599                Some(cx.spawn_in(window, async move |editor, cx| {
 5600                    let project_transaction = apply_code_action.await?;
 5601                    Self::open_project_transaction(
 5602                        &editor,
 5603                        workspace,
 5604                        project_transaction,
 5605                        title,
 5606                        cx,
 5607                    )
 5608                    .await
 5609                }))
 5610            }
 5611            CodeActionsItem::DebugScenario(scenario) => {
 5612                let context = actions_menu.actions.context.clone();
 5613
 5614                workspace.update(cx, |workspace, cx| {
 5615                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5616                });
 5617                Some(Task::ready(Ok(())))
 5618            }
 5619        }
 5620    }
 5621
 5622    pub async fn open_project_transaction(
 5623        this: &WeakEntity<Editor>,
 5624        workspace: WeakEntity<Workspace>,
 5625        transaction: ProjectTransaction,
 5626        title: String,
 5627        cx: &mut AsyncWindowContext,
 5628    ) -> Result<()> {
 5629        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5630        cx.update(|_, cx| {
 5631            entries.sort_unstable_by_key(|(buffer, _)| {
 5632                buffer.read(cx).file().map(|f| f.path().clone())
 5633            });
 5634        })?;
 5635
 5636        // If the project transaction's edits are all contained within this editor, then
 5637        // avoid opening a new editor to display them.
 5638
 5639        if let Some((buffer, transaction)) = entries.first() {
 5640            if entries.len() == 1 {
 5641                let excerpt = this.update(cx, |editor, cx| {
 5642                    editor
 5643                        .buffer()
 5644                        .read(cx)
 5645                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5646                })?;
 5647                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5648                    if excerpted_buffer == *buffer {
 5649                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5650                            let excerpt_range = excerpt_range.to_offset(buffer);
 5651                            buffer
 5652                                .edited_ranges_for_transaction::<usize>(transaction)
 5653                                .all(|range| {
 5654                                    excerpt_range.start <= range.start
 5655                                        && excerpt_range.end >= range.end
 5656                                })
 5657                        })?;
 5658
 5659                        if all_edits_within_excerpt {
 5660                            return Ok(());
 5661                        }
 5662                    }
 5663                }
 5664            }
 5665        } else {
 5666            return Ok(());
 5667        }
 5668
 5669        let mut ranges_to_highlight = Vec::new();
 5670        let excerpt_buffer = cx.new(|cx| {
 5671            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 5672            for (buffer_handle, transaction) in &entries {
 5673                let edited_ranges = buffer_handle
 5674                    .read(cx)
 5675                    .edited_ranges_for_transaction::<Point>(transaction)
 5676                    .collect::<Vec<_>>();
 5677                let (ranges, _) = multibuffer.set_excerpts_for_path(
 5678                    PathKey::for_buffer(buffer_handle, cx),
 5679                    buffer_handle.clone(),
 5680                    edited_ranges,
 5681                    DEFAULT_MULTIBUFFER_CONTEXT,
 5682                    cx,
 5683                );
 5684
 5685                ranges_to_highlight.extend(ranges);
 5686            }
 5687            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 5688            multibuffer
 5689        })?;
 5690
 5691        workspace.update_in(cx, |workspace, window, cx| {
 5692            let project = workspace.project().clone();
 5693            let editor =
 5694                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 5695            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 5696            editor.update(cx, |editor, cx| {
 5697                editor.highlight_background::<Self>(
 5698                    &ranges_to_highlight,
 5699                    |theme| theme.editor_highlighted_line_background,
 5700                    cx,
 5701                );
 5702            });
 5703        })?;
 5704
 5705        Ok(())
 5706    }
 5707
 5708    pub fn clear_code_action_providers(&mut self) {
 5709        self.code_action_providers.clear();
 5710        self.available_code_actions.take();
 5711    }
 5712
 5713    pub fn add_code_action_provider(
 5714        &mut self,
 5715        provider: Rc<dyn CodeActionProvider>,
 5716        window: &mut Window,
 5717        cx: &mut Context<Self>,
 5718    ) {
 5719        if self
 5720            .code_action_providers
 5721            .iter()
 5722            .any(|existing_provider| existing_provider.id() == provider.id())
 5723        {
 5724            return;
 5725        }
 5726
 5727        self.code_action_providers.push(provider);
 5728        self.refresh_code_actions(window, cx);
 5729    }
 5730
 5731    pub fn remove_code_action_provider(
 5732        &mut self,
 5733        id: Arc<str>,
 5734        window: &mut Window,
 5735        cx: &mut Context<Self>,
 5736    ) {
 5737        self.code_action_providers
 5738            .retain(|provider| provider.id() != id);
 5739        self.refresh_code_actions(window, cx);
 5740    }
 5741
 5742    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 5743        let newest_selection = self.selections.newest_anchor().clone();
 5744        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 5745        let buffer = self.buffer.read(cx);
 5746        if newest_selection.head().diff_base_anchor.is_some() {
 5747            return None;
 5748        }
 5749        let (start_buffer, start) =
 5750            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 5751        let (end_buffer, end) =
 5752            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 5753        if start_buffer != end_buffer {
 5754            return None;
 5755        }
 5756
 5757        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 5758            cx.background_executor()
 5759                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 5760                .await;
 5761
 5762            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 5763                let providers = this.code_action_providers.clone();
 5764                let tasks = this
 5765                    .code_action_providers
 5766                    .iter()
 5767                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 5768                    .collect::<Vec<_>>();
 5769                (providers, tasks)
 5770            })?;
 5771
 5772            let mut actions = Vec::new();
 5773            for (provider, provider_actions) in
 5774                providers.into_iter().zip(future::join_all(tasks).await)
 5775            {
 5776                if let Some(provider_actions) = provider_actions.log_err() {
 5777                    actions.extend(provider_actions.into_iter().map(|action| {
 5778                        AvailableCodeAction {
 5779                            excerpt_id: newest_selection.start.excerpt_id,
 5780                            action,
 5781                            provider: provider.clone(),
 5782                        }
 5783                    }));
 5784                }
 5785            }
 5786
 5787            this.update(cx, |this, cx| {
 5788                this.available_code_actions = if actions.is_empty() {
 5789                    None
 5790                } else {
 5791                    Some((
 5792                        Location {
 5793                            buffer: start_buffer,
 5794                            range: start..end,
 5795                        },
 5796                        actions.into(),
 5797                    ))
 5798                };
 5799                cx.notify();
 5800            })
 5801        }));
 5802        None
 5803    }
 5804
 5805    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5806        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 5807            self.show_git_blame_inline = false;
 5808
 5809            self.show_git_blame_inline_delay_task =
 5810                Some(cx.spawn_in(window, async move |this, cx| {
 5811                    cx.background_executor().timer(delay).await;
 5812
 5813                    this.update(cx, |this, cx| {
 5814                        this.show_git_blame_inline = true;
 5815                        cx.notify();
 5816                    })
 5817                    .log_err();
 5818                }));
 5819        }
 5820    }
 5821
 5822    fn show_blame_popover(
 5823        &mut self,
 5824        blame_entry: &BlameEntry,
 5825        position: gpui::Point<Pixels>,
 5826        cx: &mut Context<Self>,
 5827    ) {
 5828        if let Some(state) = &mut self.inline_blame_popover {
 5829            state.hide_task.take();
 5830            cx.notify();
 5831        } else {
 5832            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 5833            let show_task = cx.spawn(async move |editor, cx| {
 5834                cx.background_executor()
 5835                    .timer(std::time::Duration::from_millis(delay))
 5836                    .await;
 5837                editor
 5838                    .update(cx, |editor, cx| {
 5839                        if let Some(state) = &mut editor.inline_blame_popover {
 5840                            state.show_task = None;
 5841                            cx.notify();
 5842                        }
 5843                    })
 5844                    .ok();
 5845            });
 5846            let Some(blame) = self.blame.as_ref() else {
 5847                return;
 5848            };
 5849            let blame = blame.read(cx);
 5850            let details = blame.details_for_entry(&blame_entry);
 5851            let markdown = cx.new(|cx| {
 5852                Markdown::new(
 5853                    details
 5854                        .as_ref()
 5855                        .map(|message| message.message.clone())
 5856                        .unwrap_or_default(),
 5857                    None,
 5858                    None,
 5859                    cx,
 5860                )
 5861            });
 5862            self.inline_blame_popover = Some(InlineBlamePopover {
 5863                position,
 5864                show_task: Some(show_task),
 5865                hide_task: None,
 5866                popover_bounds: None,
 5867                popover_state: InlineBlamePopoverState {
 5868                    scroll_handle: ScrollHandle::new(),
 5869                    commit_message: details,
 5870                    markdown,
 5871                },
 5872            });
 5873        }
 5874    }
 5875
 5876    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 5877        if let Some(state) = &mut self.inline_blame_popover {
 5878            if state.show_task.is_some() {
 5879                self.inline_blame_popover.take();
 5880                cx.notify();
 5881            } else {
 5882                let hide_task = cx.spawn(async move |editor, cx| {
 5883                    cx.background_executor()
 5884                        .timer(std::time::Duration::from_millis(100))
 5885                        .await;
 5886                    editor
 5887                        .update(cx, |editor, cx| {
 5888                            editor.inline_blame_popover.take();
 5889                            cx.notify();
 5890                        })
 5891                        .ok();
 5892                });
 5893                state.hide_task = Some(hide_task);
 5894            }
 5895        }
 5896    }
 5897
 5898    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 5899        if self.pending_rename.is_some() {
 5900            return None;
 5901        }
 5902
 5903        let provider = self.semantics_provider.clone()?;
 5904        let buffer = self.buffer.read(cx);
 5905        let newest_selection = self.selections.newest_anchor().clone();
 5906        let cursor_position = newest_selection.head();
 5907        let (cursor_buffer, cursor_buffer_position) =
 5908            buffer.text_anchor_for_position(cursor_position, cx)?;
 5909        let (tail_buffer, tail_buffer_position) =
 5910            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 5911        if cursor_buffer != tail_buffer {
 5912            return None;
 5913        }
 5914
 5915        let snapshot = cursor_buffer.read(cx).snapshot();
 5916        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 5917        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 5918        if start_word_range != end_word_range {
 5919            self.document_highlights_task.take();
 5920            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 5921            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 5922            return None;
 5923        }
 5924
 5925        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 5926        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 5927            cx.background_executor()
 5928                .timer(Duration::from_millis(debounce))
 5929                .await;
 5930
 5931            let highlights = if let Some(highlights) = cx
 5932                .update(|cx| {
 5933                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 5934                })
 5935                .ok()
 5936                .flatten()
 5937            {
 5938                highlights.await.log_err()
 5939            } else {
 5940                None
 5941            };
 5942
 5943            if let Some(highlights) = highlights {
 5944                this.update(cx, |this, cx| {
 5945                    if this.pending_rename.is_some() {
 5946                        return;
 5947                    }
 5948
 5949                    let buffer_id = cursor_position.buffer_id;
 5950                    let buffer = this.buffer.read(cx);
 5951                    if !buffer
 5952                        .text_anchor_for_position(cursor_position, cx)
 5953                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 5954                    {
 5955                        return;
 5956                    }
 5957
 5958                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 5959                    let mut write_ranges = Vec::new();
 5960                    let mut read_ranges = Vec::new();
 5961                    for highlight in highlights {
 5962                        for (excerpt_id, excerpt_range) in
 5963                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 5964                        {
 5965                            let start = highlight
 5966                                .range
 5967                                .start
 5968                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 5969                            let end = highlight
 5970                                .range
 5971                                .end
 5972                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 5973                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 5974                                continue;
 5975                            }
 5976
 5977                            let range = Anchor {
 5978                                buffer_id,
 5979                                excerpt_id,
 5980                                text_anchor: start,
 5981                                diff_base_anchor: None,
 5982                            }..Anchor {
 5983                                buffer_id,
 5984                                excerpt_id,
 5985                                text_anchor: end,
 5986                                diff_base_anchor: None,
 5987                            };
 5988                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 5989                                write_ranges.push(range);
 5990                            } else {
 5991                                read_ranges.push(range);
 5992                            }
 5993                        }
 5994                    }
 5995
 5996                    this.highlight_background::<DocumentHighlightRead>(
 5997                        &read_ranges,
 5998                        |theme| theme.editor_document_highlight_read_background,
 5999                        cx,
 6000                    );
 6001                    this.highlight_background::<DocumentHighlightWrite>(
 6002                        &write_ranges,
 6003                        |theme| theme.editor_document_highlight_write_background,
 6004                        cx,
 6005                    );
 6006                    cx.notify();
 6007                })
 6008                .log_err();
 6009            }
 6010        }));
 6011        None
 6012    }
 6013
 6014    fn prepare_highlight_query_from_selection(
 6015        &mut self,
 6016        cx: &mut Context<Editor>,
 6017    ) -> Option<(String, Range<Anchor>)> {
 6018        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6019            return None;
 6020        }
 6021        if !EditorSettings::get_global(cx).selection_highlight {
 6022            return None;
 6023        }
 6024        if self.selections.count() != 1 || self.selections.line_mode {
 6025            return None;
 6026        }
 6027        let selection = self.selections.newest::<Point>(cx);
 6028        if selection.is_empty() || selection.start.row != selection.end.row {
 6029            return None;
 6030        }
 6031        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6032        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6033        let query = multi_buffer_snapshot
 6034            .text_for_range(selection_anchor_range.clone())
 6035            .collect::<String>();
 6036        if query.trim().is_empty() {
 6037            return None;
 6038        }
 6039        Some((query, selection_anchor_range))
 6040    }
 6041
 6042    fn update_selection_occurrence_highlights(
 6043        &mut self,
 6044        query_text: String,
 6045        query_range: Range<Anchor>,
 6046        multi_buffer_range_to_query: Range<Point>,
 6047        use_debounce: bool,
 6048        window: &mut Window,
 6049        cx: &mut Context<Editor>,
 6050    ) -> Task<()> {
 6051        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6052        cx.spawn_in(window, async move |editor, cx| {
 6053            if use_debounce {
 6054                cx.background_executor()
 6055                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6056                    .await;
 6057            }
 6058            let match_task = cx.background_spawn(async move {
 6059                let buffer_ranges = multi_buffer_snapshot
 6060                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6061                    .into_iter()
 6062                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6063                let mut match_ranges = Vec::new();
 6064                let Ok(regex) = project::search::SearchQuery::text(
 6065                    query_text.clone(),
 6066                    false,
 6067                    false,
 6068                    false,
 6069                    Default::default(),
 6070                    Default::default(),
 6071                    false,
 6072                    None,
 6073                ) else {
 6074                    return Vec::default();
 6075                };
 6076                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6077                    match_ranges.extend(
 6078                        regex
 6079                            .search(&buffer_snapshot, Some(search_range.clone()))
 6080                            .await
 6081                            .into_iter()
 6082                            .filter_map(|match_range| {
 6083                                let match_start = buffer_snapshot
 6084                                    .anchor_after(search_range.start + match_range.start);
 6085                                let match_end = buffer_snapshot
 6086                                    .anchor_before(search_range.start + match_range.end);
 6087                                let match_anchor_range = Anchor::range_in_buffer(
 6088                                    excerpt_id,
 6089                                    buffer_snapshot.remote_id(),
 6090                                    match_start..match_end,
 6091                                );
 6092                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6093                            }),
 6094                    );
 6095                }
 6096                match_ranges
 6097            });
 6098            let match_ranges = match_task.await;
 6099            editor
 6100                .update_in(cx, |editor, _, cx| {
 6101                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6102                    if !match_ranges.is_empty() {
 6103                        editor.highlight_background::<SelectedTextHighlight>(
 6104                            &match_ranges,
 6105                            |theme| theme.editor_document_highlight_bracket_background,
 6106                            cx,
 6107                        )
 6108                    }
 6109                })
 6110                .log_err();
 6111        })
 6112    }
 6113
 6114    fn refresh_selected_text_highlights(
 6115        &mut self,
 6116        on_buffer_edit: bool,
 6117        window: &mut Window,
 6118        cx: &mut Context<Editor>,
 6119    ) {
 6120        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6121        else {
 6122            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6123            self.quick_selection_highlight_task.take();
 6124            self.debounced_selection_highlight_task.take();
 6125            return;
 6126        };
 6127        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6128        if on_buffer_edit
 6129            || self
 6130                .quick_selection_highlight_task
 6131                .as_ref()
 6132                .map_or(true, |(prev_anchor_range, _)| {
 6133                    prev_anchor_range != &query_range
 6134                })
 6135        {
 6136            let multi_buffer_visible_start = self
 6137                .scroll_manager
 6138                .anchor()
 6139                .anchor
 6140                .to_point(&multi_buffer_snapshot);
 6141            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6142                multi_buffer_visible_start
 6143                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6144                Bias::Left,
 6145            );
 6146            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6147            self.quick_selection_highlight_task = Some((
 6148                query_range.clone(),
 6149                self.update_selection_occurrence_highlights(
 6150                    query_text.clone(),
 6151                    query_range.clone(),
 6152                    multi_buffer_visible_range,
 6153                    false,
 6154                    window,
 6155                    cx,
 6156                ),
 6157            ));
 6158        }
 6159        if on_buffer_edit
 6160            || self
 6161                .debounced_selection_highlight_task
 6162                .as_ref()
 6163                .map_or(true, |(prev_anchor_range, _)| {
 6164                    prev_anchor_range != &query_range
 6165                })
 6166        {
 6167            let multi_buffer_start = multi_buffer_snapshot
 6168                .anchor_before(0)
 6169                .to_point(&multi_buffer_snapshot);
 6170            let multi_buffer_end = multi_buffer_snapshot
 6171                .anchor_after(multi_buffer_snapshot.len())
 6172                .to_point(&multi_buffer_snapshot);
 6173            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6174            self.debounced_selection_highlight_task = Some((
 6175                query_range.clone(),
 6176                self.update_selection_occurrence_highlights(
 6177                    query_text,
 6178                    query_range,
 6179                    multi_buffer_full_range,
 6180                    true,
 6181                    window,
 6182                    cx,
 6183                ),
 6184            ));
 6185        }
 6186    }
 6187
 6188    pub fn refresh_inline_completion(
 6189        &mut self,
 6190        debounce: bool,
 6191        user_requested: bool,
 6192        window: &mut Window,
 6193        cx: &mut Context<Self>,
 6194    ) -> Option<()> {
 6195        let provider = self.edit_prediction_provider()?;
 6196        let cursor = self.selections.newest_anchor().head();
 6197        let (buffer, cursor_buffer_position) =
 6198            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6199
 6200        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6201            self.discard_inline_completion(false, cx);
 6202            return None;
 6203        }
 6204
 6205        if !user_requested
 6206            && (!self.should_show_edit_predictions()
 6207                || !self.is_focused(window)
 6208                || buffer.read(cx).is_empty())
 6209        {
 6210            self.discard_inline_completion(false, cx);
 6211            return None;
 6212        }
 6213
 6214        self.update_visible_inline_completion(window, cx);
 6215        provider.refresh(
 6216            self.project.clone(),
 6217            buffer,
 6218            cursor_buffer_position,
 6219            debounce,
 6220            cx,
 6221        );
 6222        Some(())
 6223    }
 6224
 6225    fn show_edit_predictions_in_menu(&self) -> bool {
 6226        match self.edit_prediction_settings {
 6227            EditPredictionSettings::Disabled => false,
 6228            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6229        }
 6230    }
 6231
 6232    pub fn edit_predictions_enabled(&self) -> bool {
 6233        match self.edit_prediction_settings {
 6234            EditPredictionSettings::Disabled => false,
 6235            EditPredictionSettings::Enabled { .. } => true,
 6236        }
 6237    }
 6238
 6239    fn edit_prediction_requires_modifier(&self) -> bool {
 6240        match self.edit_prediction_settings {
 6241            EditPredictionSettings::Disabled => false,
 6242            EditPredictionSettings::Enabled {
 6243                preview_requires_modifier,
 6244                ..
 6245            } => preview_requires_modifier,
 6246        }
 6247    }
 6248
 6249    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6250        if self.edit_prediction_provider.is_none() {
 6251            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6252        } else {
 6253            let selection = self.selections.newest_anchor();
 6254            let cursor = selection.head();
 6255
 6256            if let Some((buffer, cursor_buffer_position)) =
 6257                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6258            {
 6259                self.edit_prediction_settings =
 6260                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6261            }
 6262        }
 6263    }
 6264
 6265    fn edit_prediction_settings_at_position(
 6266        &self,
 6267        buffer: &Entity<Buffer>,
 6268        buffer_position: language::Anchor,
 6269        cx: &App,
 6270    ) -> EditPredictionSettings {
 6271        if !self.mode.is_full()
 6272            || !self.show_inline_completions_override.unwrap_or(true)
 6273            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6274        {
 6275            return EditPredictionSettings::Disabled;
 6276        }
 6277
 6278        let buffer = buffer.read(cx);
 6279
 6280        let file = buffer.file();
 6281
 6282        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6283            return EditPredictionSettings::Disabled;
 6284        };
 6285
 6286        let by_provider = matches!(
 6287            self.menu_inline_completions_policy,
 6288            MenuInlineCompletionsPolicy::ByProvider
 6289        );
 6290
 6291        let show_in_menu = by_provider
 6292            && self
 6293                .edit_prediction_provider
 6294                .as_ref()
 6295                .map_or(false, |provider| {
 6296                    provider.provider.show_completions_in_menu()
 6297                });
 6298
 6299        let preview_requires_modifier =
 6300            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6301
 6302        EditPredictionSettings::Enabled {
 6303            show_in_menu,
 6304            preview_requires_modifier,
 6305        }
 6306    }
 6307
 6308    fn should_show_edit_predictions(&self) -> bool {
 6309        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6310    }
 6311
 6312    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6313        matches!(
 6314            self.edit_prediction_preview,
 6315            EditPredictionPreview::Active { .. }
 6316        )
 6317    }
 6318
 6319    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6320        let cursor = self.selections.newest_anchor().head();
 6321        if let Some((buffer, cursor_position)) =
 6322            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6323        {
 6324            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6325        } else {
 6326            false
 6327        }
 6328    }
 6329
 6330    pub fn supports_minimap(&self, cx: &App) -> bool {
 6331        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6332    }
 6333
 6334    fn edit_predictions_enabled_in_buffer(
 6335        &self,
 6336        buffer: &Entity<Buffer>,
 6337        buffer_position: language::Anchor,
 6338        cx: &App,
 6339    ) -> bool {
 6340        maybe!({
 6341            if self.read_only(cx) {
 6342                return Some(false);
 6343            }
 6344            let provider = self.edit_prediction_provider()?;
 6345            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6346                return Some(false);
 6347            }
 6348            let buffer = buffer.read(cx);
 6349            let Some(file) = buffer.file() else {
 6350                return Some(true);
 6351            };
 6352            let settings = all_language_settings(Some(file), cx);
 6353            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6354        })
 6355        .unwrap_or(false)
 6356    }
 6357
 6358    fn cycle_inline_completion(
 6359        &mut self,
 6360        direction: Direction,
 6361        window: &mut Window,
 6362        cx: &mut Context<Self>,
 6363    ) -> Option<()> {
 6364        let provider = self.edit_prediction_provider()?;
 6365        let cursor = self.selections.newest_anchor().head();
 6366        let (buffer, cursor_buffer_position) =
 6367            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6368        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6369            return None;
 6370        }
 6371
 6372        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6373        self.update_visible_inline_completion(window, cx);
 6374
 6375        Some(())
 6376    }
 6377
 6378    pub fn show_inline_completion(
 6379        &mut self,
 6380        _: &ShowEditPrediction,
 6381        window: &mut Window,
 6382        cx: &mut Context<Self>,
 6383    ) {
 6384        if !self.has_active_inline_completion() {
 6385            self.refresh_inline_completion(false, true, window, cx);
 6386            return;
 6387        }
 6388
 6389        self.update_visible_inline_completion(window, cx);
 6390    }
 6391
 6392    pub fn display_cursor_names(
 6393        &mut self,
 6394        _: &DisplayCursorNames,
 6395        window: &mut Window,
 6396        cx: &mut Context<Self>,
 6397    ) {
 6398        self.show_cursor_names(window, cx);
 6399    }
 6400
 6401    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6402        self.show_cursor_names = true;
 6403        cx.notify();
 6404        cx.spawn_in(window, async move |this, cx| {
 6405            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6406            this.update(cx, |this, cx| {
 6407                this.show_cursor_names = false;
 6408                cx.notify()
 6409            })
 6410            .ok()
 6411        })
 6412        .detach();
 6413    }
 6414
 6415    pub fn next_edit_prediction(
 6416        &mut self,
 6417        _: &NextEditPrediction,
 6418        window: &mut Window,
 6419        cx: &mut Context<Self>,
 6420    ) {
 6421        if self.has_active_inline_completion() {
 6422            self.cycle_inline_completion(Direction::Next, window, cx);
 6423        } else {
 6424            let is_copilot_disabled = self
 6425                .refresh_inline_completion(false, true, window, cx)
 6426                .is_none();
 6427            if is_copilot_disabled {
 6428                cx.propagate();
 6429            }
 6430        }
 6431    }
 6432
 6433    pub fn previous_edit_prediction(
 6434        &mut self,
 6435        _: &PreviousEditPrediction,
 6436        window: &mut Window,
 6437        cx: &mut Context<Self>,
 6438    ) {
 6439        if self.has_active_inline_completion() {
 6440            self.cycle_inline_completion(Direction::Prev, window, cx);
 6441        } else {
 6442            let is_copilot_disabled = self
 6443                .refresh_inline_completion(false, true, window, cx)
 6444                .is_none();
 6445            if is_copilot_disabled {
 6446                cx.propagate();
 6447            }
 6448        }
 6449    }
 6450
 6451    pub fn accept_edit_prediction(
 6452        &mut self,
 6453        _: &AcceptEditPrediction,
 6454        window: &mut Window,
 6455        cx: &mut Context<Self>,
 6456    ) {
 6457        if self.show_edit_predictions_in_menu() {
 6458            self.hide_context_menu(window, cx);
 6459        }
 6460
 6461        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6462            return;
 6463        };
 6464
 6465        self.report_inline_completion_event(
 6466            active_inline_completion.completion_id.clone(),
 6467            true,
 6468            cx,
 6469        );
 6470
 6471        match &active_inline_completion.completion {
 6472            InlineCompletion::Move { target, .. } => {
 6473                let target = *target;
 6474
 6475                if let Some(position_map) = &self.last_position_map {
 6476                    if position_map
 6477                        .visible_row_range
 6478                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6479                        || !self.edit_prediction_requires_modifier()
 6480                    {
 6481                        self.unfold_ranges(&[target..target], true, false, cx);
 6482                        // Note that this is also done in vim's handler of the Tab action.
 6483                        self.change_selections(
 6484                            Some(Autoscroll::newest()),
 6485                            window,
 6486                            cx,
 6487                            |selections| {
 6488                                selections.select_anchor_ranges([target..target]);
 6489                            },
 6490                        );
 6491                        self.clear_row_highlights::<EditPredictionPreview>();
 6492
 6493                        self.edit_prediction_preview
 6494                            .set_previous_scroll_position(None);
 6495                    } else {
 6496                        self.edit_prediction_preview
 6497                            .set_previous_scroll_position(Some(
 6498                                position_map.snapshot.scroll_anchor,
 6499                            ));
 6500
 6501                        self.highlight_rows::<EditPredictionPreview>(
 6502                            target..target,
 6503                            cx.theme().colors().editor_highlighted_line_background,
 6504                            RowHighlightOptions {
 6505                                autoscroll: true,
 6506                                ..Default::default()
 6507                            },
 6508                            cx,
 6509                        );
 6510                        self.request_autoscroll(Autoscroll::fit(), cx);
 6511                    }
 6512                }
 6513            }
 6514            InlineCompletion::Edit { edits, .. } => {
 6515                if let Some(provider) = self.edit_prediction_provider() {
 6516                    provider.accept(cx);
 6517                }
 6518
 6519                let snapshot = self.buffer.read(cx).snapshot(cx);
 6520                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6521
 6522                self.buffer.update(cx, |buffer, cx| {
 6523                    buffer.edit(edits.iter().cloned(), None, cx)
 6524                });
 6525
 6526                self.change_selections(None, window, cx, |s| {
 6527                    s.select_anchor_ranges([last_edit_end..last_edit_end])
 6528                });
 6529
 6530                self.update_visible_inline_completion(window, cx);
 6531                if self.active_inline_completion.is_none() {
 6532                    self.refresh_inline_completion(true, true, window, cx);
 6533                }
 6534
 6535                cx.notify();
 6536            }
 6537        }
 6538
 6539        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6540    }
 6541
 6542    pub fn accept_partial_inline_completion(
 6543        &mut self,
 6544        _: &AcceptPartialEditPrediction,
 6545        window: &mut Window,
 6546        cx: &mut Context<Self>,
 6547    ) {
 6548        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6549            return;
 6550        };
 6551        if self.selections.count() != 1 {
 6552            return;
 6553        }
 6554
 6555        self.report_inline_completion_event(
 6556            active_inline_completion.completion_id.clone(),
 6557            true,
 6558            cx,
 6559        );
 6560
 6561        match &active_inline_completion.completion {
 6562            InlineCompletion::Move { target, .. } => {
 6563                let target = *target;
 6564                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6565                    selections.select_anchor_ranges([target..target]);
 6566                });
 6567            }
 6568            InlineCompletion::Edit { edits, .. } => {
 6569                // Find an insertion that starts at the cursor position.
 6570                let snapshot = self.buffer.read(cx).snapshot(cx);
 6571                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6572                let insertion = edits.iter().find_map(|(range, text)| {
 6573                    let range = range.to_offset(&snapshot);
 6574                    if range.is_empty() && range.start == cursor_offset {
 6575                        Some(text)
 6576                    } else {
 6577                        None
 6578                    }
 6579                });
 6580
 6581                if let Some(text) = insertion {
 6582                    let mut partial_completion = text
 6583                        .chars()
 6584                        .by_ref()
 6585                        .take_while(|c| c.is_alphabetic())
 6586                        .collect::<String>();
 6587                    if partial_completion.is_empty() {
 6588                        partial_completion = text
 6589                            .chars()
 6590                            .by_ref()
 6591                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 6592                            .collect::<String>();
 6593                    }
 6594
 6595                    cx.emit(EditorEvent::InputHandled {
 6596                        utf16_range_to_replace: None,
 6597                        text: partial_completion.clone().into(),
 6598                    });
 6599
 6600                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 6601
 6602                    self.refresh_inline_completion(true, true, window, cx);
 6603                    cx.notify();
 6604                } else {
 6605                    self.accept_edit_prediction(&Default::default(), window, cx);
 6606                }
 6607            }
 6608        }
 6609    }
 6610
 6611    fn discard_inline_completion(
 6612        &mut self,
 6613        should_report_inline_completion_event: bool,
 6614        cx: &mut Context<Self>,
 6615    ) -> bool {
 6616        if should_report_inline_completion_event {
 6617            let completion_id = self
 6618                .active_inline_completion
 6619                .as_ref()
 6620                .and_then(|active_completion| active_completion.completion_id.clone());
 6621
 6622            self.report_inline_completion_event(completion_id, false, cx);
 6623        }
 6624
 6625        if let Some(provider) = self.edit_prediction_provider() {
 6626            provider.discard(cx);
 6627        }
 6628
 6629        self.take_active_inline_completion(cx)
 6630    }
 6631
 6632    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 6633        let Some(provider) = self.edit_prediction_provider() else {
 6634            return;
 6635        };
 6636
 6637        let Some((_, buffer, _)) = self
 6638            .buffer
 6639            .read(cx)
 6640            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 6641        else {
 6642            return;
 6643        };
 6644
 6645        let extension = buffer
 6646            .read(cx)
 6647            .file()
 6648            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 6649
 6650        let event_type = match accepted {
 6651            true => "Edit Prediction Accepted",
 6652            false => "Edit Prediction Discarded",
 6653        };
 6654        telemetry::event!(
 6655            event_type,
 6656            provider = provider.name(),
 6657            prediction_id = id,
 6658            suggestion_accepted = accepted,
 6659            file_extension = extension,
 6660        );
 6661    }
 6662
 6663    pub fn has_active_inline_completion(&self) -> bool {
 6664        self.active_inline_completion.is_some()
 6665    }
 6666
 6667    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 6668        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 6669            return false;
 6670        };
 6671
 6672        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 6673        self.clear_highlights::<InlineCompletionHighlight>(cx);
 6674        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 6675        true
 6676    }
 6677
 6678    /// Returns true when we're displaying the edit prediction popover below the cursor
 6679    /// like we are not previewing and the LSP autocomplete menu is visible
 6680    /// or we are in `when_holding_modifier` mode.
 6681    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 6682        if self.edit_prediction_preview_is_active()
 6683            || !self.show_edit_predictions_in_menu()
 6684            || !self.edit_predictions_enabled()
 6685        {
 6686            return false;
 6687        }
 6688
 6689        if self.has_visible_completions_menu() {
 6690            return true;
 6691        }
 6692
 6693        has_completion && self.edit_prediction_requires_modifier()
 6694    }
 6695
 6696    fn handle_modifiers_changed(
 6697        &mut self,
 6698        modifiers: Modifiers,
 6699        position_map: &PositionMap,
 6700        window: &mut Window,
 6701        cx: &mut Context<Self>,
 6702    ) {
 6703        if self.show_edit_predictions_in_menu() {
 6704            self.update_edit_prediction_preview(&modifiers, window, cx);
 6705        }
 6706
 6707        self.update_selection_mode(&modifiers, position_map, window, cx);
 6708
 6709        let mouse_position = window.mouse_position();
 6710        if !position_map.text_hitbox.is_hovered(window) {
 6711            return;
 6712        }
 6713
 6714        self.update_hovered_link(
 6715            position_map.point_for_position(mouse_position),
 6716            &position_map.snapshot,
 6717            modifiers,
 6718            window,
 6719            cx,
 6720        )
 6721    }
 6722
 6723    fn update_selection_mode(
 6724        &mut self,
 6725        modifiers: &Modifiers,
 6726        position_map: &PositionMap,
 6727        window: &mut Window,
 6728        cx: &mut Context<Self>,
 6729    ) {
 6730        if modifiers != &COLUMNAR_SELECTION_MODIFIERS || self.selections.pending.is_none() {
 6731            return;
 6732        }
 6733
 6734        let mouse_position = window.mouse_position();
 6735        let point_for_position = position_map.point_for_position(mouse_position);
 6736        let position = point_for_position.previous_valid;
 6737
 6738        self.select(
 6739            SelectPhase::BeginColumnar {
 6740                position,
 6741                reset: false,
 6742                goal_column: point_for_position.exact_unclipped.column(),
 6743            },
 6744            window,
 6745            cx,
 6746        );
 6747    }
 6748
 6749    fn update_edit_prediction_preview(
 6750        &mut self,
 6751        modifiers: &Modifiers,
 6752        window: &mut Window,
 6753        cx: &mut Context<Self>,
 6754    ) {
 6755        let accept_keybind = self.accept_edit_prediction_keybind(window, cx);
 6756        let Some(accept_keystroke) = accept_keybind.keystroke() else {
 6757            return;
 6758        };
 6759
 6760        if &accept_keystroke.modifiers == modifiers && accept_keystroke.modifiers.modified() {
 6761            if matches!(
 6762                self.edit_prediction_preview,
 6763                EditPredictionPreview::Inactive { .. }
 6764            ) {
 6765                self.edit_prediction_preview = EditPredictionPreview::Active {
 6766                    previous_scroll_position: None,
 6767                    since: Instant::now(),
 6768                };
 6769
 6770                self.update_visible_inline_completion(window, cx);
 6771                cx.notify();
 6772            }
 6773        } else if let EditPredictionPreview::Active {
 6774            previous_scroll_position,
 6775            since,
 6776        } = self.edit_prediction_preview
 6777        {
 6778            if let (Some(previous_scroll_position), Some(position_map)) =
 6779                (previous_scroll_position, self.last_position_map.as_ref())
 6780            {
 6781                self.set_scroll_position(
 6782                    previous_scroll_position
 6783                        .scroll_position(&position_map.snapshot.display_snapshot),
 6784                    window,
 6785                    cx,
 6786                );
 6787            }
 6788
 6789            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 6790                released_too_fast: since.elapsed() < Duration::from_millis(200),
 6791            };
 6792            self.clear_row_highlights::<EditPredictionPreview>();
 6793            self.update_visible_inline_completion(window, cx);
 6794            cx.notify();
 6795        }
 6796    }
 6797
 6798    fn update_visible_inline_completion(
 6799        &mut self,
 6800        _window: &mut Window,
 6801        cx: &mut Context<Self>,
 6802    ) -> Option<()> {
 6803        let selection = self.selections.newest_anchor();
 6804        let cursor = selection.head();
 6805        let multibuffer = self.buffer.read(cx).snapshot(cx);
 6806        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 6807        let excerpt_id = cursor.excerpt_id;
 6808
 6809        let show_in_menu = self.show_edit_predictions_in_menu();
 6810        let completions_menu_has_precedence = !show_in_menu
 6811            && (self.context_menu.borrow().is_some()
 6812                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 6813
 6814        if completions_menu_has_precedence
 6815            || !offset_selection.is_empty()
 6816            || self
 6817                .active_inline_completion
 6818                .as_ref()
 6819                .map_or(false, |completion| {
 6820                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 6821                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 6822                    !invalidation_range.contains(&offset_selection.head())
 6823                })
 6824        {
 6825            self.discard_inline_completion(false, cx);
 6826            return None;
 6827        }
 6828
 6829        self.take_active_inline_completion(cx);
 6830        let Some(provider) = self.edit_prediction_provider() else {
 6831            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6832            return None;
 6833        };
 6834
 6835        let (buffer, cursor_buffer_position) =
 6836            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6837
 6838        self.edit_prediction_settings =
 6839            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6840
 6841        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 6842
 6843        if self.edit_prediction_indent_conflict {
 6844            let cursor_point = cursor.to_point(&multibuffer);
 6845
 6846            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 6847
 6848            if let Some((_, indent)) = indents.iter().next() {
 6849                if indent.len == cursor_point.column {
 6850                    self.edit_prediction_indent_conflict = false;
 6851                }
 6852            }
 6853        }
 6854
 6855        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 6856        let edits = inline_completion
 6857            .edits
 6858            .into_iter()
 6859            .flat_map(|(range, new_text)| {
 6860                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 6861                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 6862                Some((start..end, new_text))
 6863            })
 6864            .collect::<Vec<_>>();
 6865        if edits.is_empty() {
 6866            return None;
 6867        }
 6868
 6869        let first_edit_start = edits.first().unwrap().0.start;
 6870        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 6871        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 6872
 6873        let last_edit_end = edits.last().unwrap().0.end;
 6874        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 6875        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 6876
 6877        let cursor_row = cursor.to_point(&multibuffer).row;
 6878
 6879        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 6880
 6881        let mut inlay_ids = Vec::new();
 6882        let invalidation_row_range;
 6883        let move_invalidation_row_range = if cursor_row < edit_start_row {
 6884            Some(cursor_row..edit_end_row)
 6885        } else if cursor_row > edit_end_row {
 6886            Some(edit_start_row..cursor_row)
 6887        } else {
 6888            None
 6889        };
 6890        let is_move =
 6891            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 6892        let completion = if is_move {
 6893            invalidation_row_range =
 6894                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 6895            let target = first_edit_start;
 6896            InlineCompletion::Move { target, snapshot }
 6897        } else {
 6898            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 6899                && !self.inline_completions_hidden_for_vim_mode;
 6900
 6901            if show_completions_in_buffer {
 6902                if edits
 6903                    .iter()
 6904                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 6905                {
 6906                    let mut inlays = Vec::new();
 6907                    for (range, new_text) in &edits {
 6908                        let inlay = Inlay::inline_completion(
 6909                            post_inc(&mut self.next_inlay_id),
 6910                            range.start,
 6911                            new_text.as_str(),
 6912                        );
 6913                        inlay_ids.push(inlay.id);
 6914                        inlays.push(inlay);
 6915                    }
 6916
 6917                    self.splice_inlays(&[], inlays, cx);
 6918                } else {
 6919                    let background_color = cx.theme().status().deleted_background;
 6920                    self.highlight_text::<InlineCompletionHighlight>(
 6921                        edits.iter().map(|(range, _)| range.clone()).collect(),
 6922                        HighlightStyle {
 6923                            background_color: Some(background_color),
 6924                            ..Default::default()
 6925                        },
 6926                        cx,
 6927                    );
 6928                }
 6929            }
 6930
 6931            invalidation_row_range = edit_start_row..edit_end_row;
 6932
 6933            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 6934                if provider.show_tab_accept_marker() {
 6935                    EditDisplayMode::TabAccept
 6936                } else {
 6937                    EditDisplayMode::Inline
 6938                }
 6939            } else {
 6940                EditDisplayMode::DiffPopover
 6941            };
 6942
 6943            InlineCompletion::Edit {
 6944                edits,
 6945                edit_preview: inline_completion.edit_preview,
 6946                display_mode,
 6947                snapshot,
 6948            }
 6949        };
 6950
 6951        let invalidation_range = multibuffer
 6952            .anchor_before(Point::new(invalidation_row_range.start, 0))
 6953            ..multibuffer.anchor_after(Point::new(
 6954                invalidation_row_range.end,
 6955                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 6956            ));
 6957
 6958        self.stale_inline_completion_in_menu = None;
 6959        self.active_inline_completion = Some(InlineCompletionState {
 6960            inlay_ids,
 6961            completion,
 6962            completion_id: inline_completion.id,
 6963            invalidation_range,
 6964        });
 6965
 6966        cx.notify();
 6967
 6968        Some(())
 6969    }
 6970
 6971    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 6972        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 6973    }
 6974
 6975    fn clear_tasks(&mut self) {
 6976        self.tasks.clear()
 6977    }
 6978
 6979    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 6980        if self.tasks.insert(key, value).is_some() {
 6981            // This case should hopefully be rare, but just in case...
 6982            log::error!(
 6983                "multiple different run targets found on a single line, only the last target will be rendered"
 6984            )
 6985        }
 6986    }
 6987
 6988    /// Get all display points of breakpoints that will be rendered within editor
 6989    ///
 6990    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 6991    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 6992    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 6993    fn active_breakpoints(
 6994        &self,
 6995        range: Range<DisplayRow>,
 6996        window: &mut Window,
 6997        cx: &mut Context<Self>,
 6998    ) -> HashMap<DisplayRow, (Anchor, Breakpoint)> {
 6999        let mut breakpoint_display_points = HashMap::default();
 7000
 7001        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7002            return breakpoint_display_points;
 7003        };
 7004
 7005        let snapshot = self.snapshot(window, cx);
 7006
 7007        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7008        let Some(project) = self.project.as_ref() else {
 7009            return breakpoint_display_points;
 7010        };
 7011
 7012        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7013            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7014
 7015        for (buffer_snapshot, range, excerpt_id) in
 7016            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7017        {
 7018            let Some(buffer) = project.read_with(cx, |this, cx| {
 7019                this.buffer_for_id(buffer_snapshot.remote_id(), cx)
 7020            }) else {
 7021                continue;
 7022            };
 7023            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7024                &buffer,
 7025                Some(
 7026                    buffer_snapshot.anchor_before(range.start)
 7027                        ..buffer_snapshot.anchor_after(range.end),
 7028                ),
 7029                buffer_snapshot,
 7030                cx,
 7031            );
 7032            for (anchor, breakpoint) in breakpoints {
 7033                let multi_buffer_anchor =
 7034                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), *anchor);
 7035                let position = multi_buffer_anchor
 7036                    .to_point(&multi_buffer_snapshot)
 7037                    .to_display_point(&snapshot);
 7038
 7039                breakpoint_display_points
 7040                    .insert(position.row(), (multi_buffer_anchor, breakpoint.clone()));
 7041            }
 7042        }
 7043
 7044        breakpoint_display_points
 7045    }
 7046
 7047    fn breakpoint_context_menu(
 7048        &self,
 7049        anchor: Anchor,
 7050        window: &mut Window,
 7051        cx: &mut Context<Self>,
 7052    ) -> Entity<ui::ContextMenu> {
 7053        let weak_editor = cx.weak_entity();
 7054        let focus_handle = self.focus_handle(cx);
 7055
 7056        let row = self
 7057            .buffer
 7058            .read(cx)
 7059            .snapshot(cx)
 7060            .summary_for_anchor::<Point>(&anchor)
 7061            .row;
 7062
 7063        let breakpoint = self
 7064            .breakpoint_at_row(row, window, cx)
 7065            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7066
 7067        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7068            "Edit Log Breakpoint"
 7069        } else {
 7070            "Set Log Breakpoint"
 7071        };
 7072
 7073        let condition_breakpoint_msg = if breakpoint
 7074            .as_ref()
 7075            .is_some_and(|bp| bp.1.condition.is_some())
 7076        {
 7077            "Edit Condition Breakpoint"
 7078        } else {
 7079            "Set Condition Breakpoint"
 7080        };
 7081
 7082        let hit_condition_breakpoint_msg = if breakpoint
 7083            .as_ref()
 7084            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7085        {
 7086            "Edit Hit Condition Breakpoint"
 7087        } else {
 7088            "Set Hit Condition Breakpoint"
 7089        };
 7090
 7091        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7092            "Unset Breakpoint"
 7093        } else {
 7094            "Set Breakpoint"
 7095        };
 7096
 7097        let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx)
 7098            .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor));
 7099
 7100        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7101            BreakpointState::Enabled => Some("Disable"),
 7102            BreakpointState::Disabled => Some("Enable"),
 7103        });
 7104
 7105        let (anchor, breakpoint) =
 7106            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7107
 7108        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7109            menu.on_blur_subscription(Subscription::new(|| {}))
 7110                .context(focus_handle)
 7111                .when(run_to_cursor, |this| {
 7112                    let weak_editor = weak_editor.clone();
 7113                    this.entry("Run to cursor", None, move |window, cx| {
 7114                        weak_editor
 7115                            .update(cx, |editor, cx| {
 7116                                editor.change_selections(None, window, cx, |s| {
 7117                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7118                                });
 7119                            })
 7120                            .ok();
 7121
 7122                        window.dispatch_action(Box::new(DebuggerRunToCursor), cx);
 7123                    })
 7124                    .separator()
 7125                })
 7126                .when_some(toggle_state_msg, |this, msg| {
 7127                    this.entry(msg, None, {
 7128                        let weak_editor = weak_editor.clone();
 7129                        let breakpoint = breakpoint.clone();
 7130                        move |_window, cx| {
 7131                            weak_editor
 7132                                .update(cx, |this, cx| {
 7133                                    this.edit_breakpoint_at_anchor(
 7134                                        anchor,
 7135                                        breakpoint.as_ref().clone(),
 7136                                        BreakpointEditAction::InvertState,
 7137                                        cx,
 7138                                    );
 7139                                })
 7140                                .log_err();
 7141                        }
 7142                    })
 7143                })
 7144                .entry(set_breakpoint_msg, None, {
 7145                    let weak_editor = weak_editor.clone();
 7146                    let breakpoint = breakpoint.clone();
 7147                    move |_window, cx| {
 7148                        weak_editor
 7149                            .update(cx, |this, cx| {
 7150                                this.edit_breakpoint_at_anchor(
 7151                                    anchor,
 7152                                    breakpoint.as_ref().clone(),
 7153                                    BreakpointEditAction::Toggle,
 7154                                    cx,
 7155                                );
 7156                            })
 7157                            .log_err();
 7158                    }
 7159                })
 7160                .entry(log_breakpoint_msg, None, {
 7161                    let breakpoint = breakpoint.clone();
 7162                    let weak_editor = weak_editor.clone();
 7163                    move |window, cx| {
 7164                        weak_editor
 7165                            .update(cx, |this, cx| {
 7166                                this.add_edit_breakpoint_block(
 7167                                    anchor,
 7168                                    breakpoint.as_ref(),
 7169                                    BreakpointPromptEditAction::Log,
 7170                                    window,
 7171                                    cx,
 7172                                );
 7173                            })
 7174                            .log_err();
 7175                    }
 7176                })
 7177                .entry(condition_breakpoint_msg, None, {
 7178                    let breakpoint = breakpoint.clone();
 7179                    let weak_editor = weak_editor.clone();
 7180                    move |window, cx| {
 7181                        weak_editor
 7182                            .update(cx, |this, cx| {
 7183                                this.add_edit_breakpoint_block(
 7184                                    anchor,
 7185                                    breakpoint.as_ref(),
 7186                                    BreakpointPromptEditAction::Condition,
 7187                                    window,
 7188                                    cx,
 7189                                );
 7190                            })
 7191                            .log_err();
 7192                    }
 7193                })
 7194                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7195                    weak_editor
 7196                        .update(cx, |this, cx| {
 7197                            this.add_edit_breakpoint_block(
 7198                                anchor,
 7199                                breakpoint.as_ref(),
 7200                                BreakpointPromptEditAction::HitCondition,
 7201                                window,
 7202                                cx,
 7203                            );
 7204                        })
 7205                        .log_err();
 7206                })
 7207        })
 7208    }
 7209
 7210    fn render_breakpoint(
 7211        &self,
 7212        position: Anchor,
 7213        row: DisplayRow,
 7214        breakpoint: &Breakpoint,
 7215        cx: &mut Context<Self>,
 7216    ) -> IconButton {
 7217        // Is it a breakpoint that shows up when hovering over gutter?
 7218        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7219            (false, false),
 7220            |PhantomBreakpointIndicator {
 7221                 is_active,
 7222                 display_row,
 7223                 collides_with_existing_breakpoint,
 7224             }| {
 7225                (
 7226                    is_active && display_row == row,
 7227                    collides_with_existing_breakpoint,
 7228                )
 7229            },
 7230        );
 7231
 7232        let (color, icon) = {
 7233            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7234                (false, false) => ui::IconName::DebugBreakpoint,
 7235                (true, false) => ui::IconName::DebugLogBreakpoint,
 7236                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7237                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7238            };
 7239
 7240            let color = if is_phantom {
 7241                Color::Hint
 7242            } else {
 7243                Color::Debugger
 7244            };
 7245
 7246            (color, icon)
 7247        };
 7248
 7249        let breakpoint = Arc::from(breakpoint.clone());
 7250
 7251        let alt_as_text = gpui::Keystroke {
 7252            modifiers: Modifiers::secondary_key(),
 7253            ..Default::default()
 7254        };
 7255        let primary_action_text = if breakpoint.is_disabled() {
 7256            "enable"
 7257        } else if is_phantom && !collides_with_existing {
 7258            "set"
 7259        } else {
 7260            "unset"
 7261        };
 7262        let mut primary_text = format!("Click to {primary_action_text}");
 7263        if collides_with_existing && !breakpoint.is_disabled() {
 7264            use std::fmt::Write;
 7265            write!(primary_text, ", {alt_as_text}-click to disable").ok();
 7266        }
 7267        let primary_text = SharedString::from(primary_text);
 7268        let focus_handle = self.focus_handle.clone();
 7269        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7270            .icon_size(IconSize::XSmall)
 7271            .size(ui::ButtonSize::None)
 7272            .icon_color(color)
 7273            .style(ButtonStyle::Transparent)
 7274            .on_click(cx.listener({
 7275                let breakpoint = breakpoint.clone();
 7276
 7277                move |editor, event: &ClickEvent, window, cx| {
 7278                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7279                        BreakpointEditAction::InvertState
 7280                    } else {
 7281                        BreakpointEditAction::Toggle
 7282                    };
 7283
 7284                    window.focus(&editor.focus_handle(cx));
 7285                    editor.edit_breakpoint_at_anchor(
 7286                        position,
 7287                        breakpoint.as_ref().clone(),
 7288                        edit_action,
 7289                        cx,
 7290                    );
 7291                }
 7292            }))
 7293            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7294                editor.set_breakpoint_context_menu(
 7295                    row,
 7296                    Some(position),
 7297                    event.down.position,
 7298                    window,
 7299                    cx,
 7300                );
 7301            }))
 7302            .tooltip(move |window, cx| {
 7303                Tooltip::with_meta_in(
 7304                    primary_text.clone(),
 7305                    None,
 7306                    "Right-click for more options",
 7307                    &focus_handle,
 7308                    window,
 7309                    cx,
 7310                )
 7311            })
 7312    }
 7313
 7314    fn build_tasks_context(
 7315        project: &Entity<Project>,
 7316        buffer: &Entity<Buffer>,
 7317        buffer_row: u32,
 7318        tasks: &Arc<RunnableTasks>,
 7319        cx: &mut Context<Self>,
 7320    ) -> Task<Option<task::TaskContext>> {
 7321        let position = Point::new(buffer_row, tasks.column);
 7322        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7323        let location = Location {
 7324            buffer: buffer.clone(),
 7325            range: range_start..range_start,
 7326        };
 7327        // Fill in the environmental variables from the tree-sitter captures
 7328        let mut captured_task_variables = TaskVariables::default();
 7329        for (capture_name, value) in tasks.extra_variables.clone() {
 7330            captured_task_variables.insert(
 7331                task::VariableName::Custom(capture_name.into()),
 7332                value.clone(),
 7333            );
 7334        }
 7335        project.update(cx, |project, cx| {
 7336            project.task_store().update(cx, |task_store, cx| {
 7337                task_store.task_context_for_location(captured_task_variables, location, cx)
 7338            })
 7339        })
 7340    }
 7341
 7342    pub fn spawn_nearest_task(
 7343        &mut self,
 7344        action: &SpawnNearestTask,
 7345        window: &mut Window,
 7346        cx: &mut Context<Self>,
 7347    ) {
 7348        let Some((workspace, _)) = self.workspace.clone() else {
 7349            return;
 7350        };
 7351        let Some(project) = self.project.clone() else {
 7352            return;
 7353        };
 7354
 7355        // Try to find a closest, enclosing node using tree-sitter that has a
 7356        // task
 7357        let Some((buffer, buffer_row, tasks)) = self
 7358            .find_enclosing_node_task(cx)
 7359            // Or find the task that's closest in row-distance.
 7360            .or_else(|| self.find_closest_task(cx))
 7361        else {
 7362            return;
 7363        };
 7364
 7365        let reveal_strategy = action.reveal;
 7366        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7367        cx.spawn_in(window, async move |_, cx| {
 7368            let context = task_context.await?;
 7369            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7370
 7371            let resolved = &mut resolved_task.resolved;
 7372            resolved.reveal = reveal_strategy;
 7373
 7374            workspace
 7375                .update_in(cx, |workspace, window, cx| {
 7376                    workspace.schedule_resolved_task(
 7377                        task_source_kind,
 7378                        resolved_task,
 7379                        false,
 7380                        window,
 7381                        cx,
 7382                    );
 7383                })
 7384                .ok()
 7385        })
 7386        .detach();
 7387    }
 7388
 7389    fn find_closest_task(
 7390        &mut self,
 7391        cx: &mut Context<Self>,
 7392    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7393        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7394
 7395        let ((buffer_id, row), tasks) = self
 7396            .tasks
 7397            .iter()
 7398            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7399
 7400        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7401        let tasks = Arc::new(tasks.to_owned());
 7402        Some((buffer, *row, tasks))
 7403    }
 7404
 7405    fn find_enclosing_node_task(
 7406        &mut self,
 7407        cx: &mut Context<Self>,
 7408    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7409        let snapshot = self.buffer.read(cx).snapshot(cx);
 7410        let offset = self.selections.newest::<usize>(cx).head();
 7411        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7412        let buffer_id = excerpt.buffer().remote_id();
 7413
 7414        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7415        let mut cursor = layer.node().walk();
 7416
 7417        while cursor.goto_first_child_for_byte(offset).is_some() {
 7418            if cursor.node().end_byte() == offset {
 7419                cursor.goto_next_sibling();
 7420            }
 7421        }
 7422
 7423        // Ascend to the smallest ancestor that contains the range and has a task.
 7424        loop {
 7425            let node = cursor.node();
 7426            let node_range = node.byte_range();
 7427            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7428
 7429            // Check if this node contains our offset
 7430            if node_range.start <= offset && node_range.end >= offset {
 7431                // If it contains offset, check for task
 7432                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7433                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7434                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7435                }
 7436            }
 7437
 7438            if !cursor.goto_parent() {
 7439                break;
 7440            }
 7441        }
 7442        None
 7443    }
 7444
 7445    fn render_run_indicator(
 7446        &self,
 7447        _style: &EditorStyle,
 7448        is_active: bool,
 7449        row: DisplayRow,
 7450        breakpoint: Option<(Anchor, Breakpoint)>,
 7451        cx: &mut Context<Self>,
 7452    ) -> IconButton {
 7453        let color = Color::Muted;
 7454        let position = breakpoint.as_ref().map(|(anchor, _)| *anchor);
 7455
 7456        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7457            .shape(ui::IconButtonShape::Square)
 7458            .icon_size(IconSize::XSmall)
 7459            .icon_color(color)
 7460            .toggle_state(is_active)
 7461            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7462                let quick_launch = e.down.button == MouseButton::Left;
 7463                window.focus(&editor.focus_handle(cx));
 7464                editor.toggle_code_actions(
 7465                    &ToggleCodeActions {
 7466                        deployed_from_indicator: Some(row),
 7467                        quick_launch,
 7468                    },
 7469                    window,
 7470                    cx,
 7471                );
 7472            }))
 7473            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7474                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7475            }))
 7476    }
 7477
 7478    pub fn context_menu_visible(&self) -> bool {
 7479        !self.edit_prediction_preview_is_active()
 7480            && self
 7481                .context_menu
 7482                .borrow()
 7483                .as_ref()
 7484                .map_or(false, |menu| menu.visible())
 7485    }
 7486
 7487    fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7488        self.context_menu
 7489            .borrow()
 7490            .as_ref()
 7491            .map(|menu| menu.origin())
 7492    }
 7493
 7494    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7495        self.context_menu_options = Some(options);
 7496    }
 7497
 7498    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7499    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7500
 7501    fn render_edit_prediction_popover(
 7502        &mut self,
 7503        text_bounds: &Bounds<Pixels>,
 7504        content_origin: gpui::Point<Pixels>,
 7505        right_margin: Pixels,
 7506        editor_snapshot: &EditorSnapshot,
 7507        visible_row_range: Range<DisplayRow>,
 7508        scroll_top: f32,
 7509        scroll_bottom: f32,
 7510        line_layouts: &[LineWithInvisibles],
 7511        line_height: Pixels,
 7512        scroll_pixel_position: gpui::Point<Pixels>,
 7513        newest_selection_head: Option<DisplayPoint>,
 7514        editor_width: Pixels,
 7515        style: &EditorStyle,
 7516        window: &mut Window,
 7517        cx: &mut App,
 7518    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7519        if self.mode().is_minimap() {
 7520            return None;
 7521        }
 7522        let active_inline_completion = self.active_inline_completion.as_ref()?;
 7523
 7524        if self.edit_prediction_visible_in_cursor_popover(true) {
 7525            return None;
 7526        }
 7527
 7528        match &active_inline_completion.completion {
 7529            InlineCompletion::Move { target, .. } => {
 7530                let target_display_point = target.to_display_point(editor_snapshot);
 7531
 7532                if self.edit_prediction_requires_modifier() {
 7533                    if !self.edit_prediction_preview_is_active() {
 7534                        return None;
 7535                    }
 7536
 7537                    self.render_edit_prediction_modifier_jump_popover(
 7538                        text_bounds,
 7539                        content_origin,
 7540                        visible_row_range,
 7541                        line_layouts,
 7542                        line_height,
 7543                        scroll_pixel_position,
 7544                        newest_selection_head,
 7545                        target_display_point,
 7546                        window,
 7547                        cx,
 7548                    )
 7549                } else {
 7550                    self.render_edit_prediction_eager_jump_popover(
 7551                        text_bounds,
 7552                        content_origin,
 7553                        editor_snapshot,
 7554                        visible_row_range,
 7555                        scroll_top,
 7556                        scroll_bottom,
 7557                        line_height,
 7558                        scroll_pixel_position,
 7559                        target_display_point,
 7560                        editor_width,
 7561                        window,
 7562                        cx,
 7563                    )
 7564                }
 7565            }
 7566            InlineCompletion::Edit {
 7567                display_mode: EditDisplayMode::Inline,
 7568                ..
 7569            } => None,
 7570            InlineCompletion::Edit {
 7571                display_mode: EditDisplayMode::TabAccept,
 7572                edits,
 7573                ..
 7574            } => {
 7575                let range = &edits.first()?.0;
 7576                let target_display_point = range.end.to_display_point(editor_snapshot);
 7577
 7578                self.render_edit_prediction_end_of_line_popover(
 7579                    "Accept",
 7580                    editor_snapshot,
 7581                    visible_row_range,
 7582                    target_display_point,
 7583                    line_height,
 7584                    scroll_pixel_position,
 7585                    content_origin,
 7586                    editor_width,
 7587                    window,
 7588                    cx,
 7589                )
 7590            }
 7591            InlineCompletion::Edit {
 7592                edits,
 7593                edit_preview,
 7594                display_mode: EditDisplayMode::DiffPopover,
 7595                snapshot,
 7596            } => self.render_edit_prediction_diff_popover(
 7597                text_bounds,
 7598                content_origin,
 7599                right_margin,
 7600                editor_snapshot,
 7601                visible_row_range,
 7602                line_layouts,
 7603                line_height,
 7604                scroll_pixel_position,
 7605                newest_selection_head,
 7606                editor_width,
 7607                style,
 7608                edits,
 7609                edit_preview,
 7610                snapshot,
 7611                window,
 7612                cx,
 7613            ),
 7614        }
 7615    }
 7616
 7617    fn render_edit_prediction_modifier_jump_popover(
 7618        &mut self,
 7619        text_bounds: &Bounds<Pixels>,
 7620        content_origin: gpui::Point<Pixels>,
 7621        visible_row_range: Range<DisplayRow>,
 7622        line_layouts: &[LineWithInvisibles],
 7623        line_height: Pixels,
 7624        scroll_pixel_position: gpui::Point<Pixels>,
 7625        newest_selection_head: Option<DisplayPoint>,
 7626        target_display_point: DisplayPoint,
 7627        window: &mut Window,
 7628        cx: &mut App,
 7629    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7630        let scrolled_content_origin =
 7631            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 7632
 7633        const SCROLL_PADDING_Y: Pixels = px(12.);
 7634
 7635        if target_display_point.row() < visible_row_range.start {
 7636            return self.render_edit_prediction_scroll_popover(
 7637                |_| SCROLL_PADDING_Y,
 7638                IconName::ArrowUp,
 7639                visible_row_range,
 7640                line_layouts,
 7641                newest_selection_head,
 7642                scrolled_content_origin,
 7643                window,
 7644                cx,
 7645            );
 7646        } else if target_display_point.row() >= visible_row_range.end {
 7647            return self.render_edit_prediction_scroll_popover(
 7648                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 7649                IconName::ArrowDown,
 7650                visible_row_range,
 7651                line_layouts,
 7652                newest_selection_head,
 7653                scrolled_content_origin,
 7654                window,
 7655                cx,
 7656            );
 7657        }
 7658
 7659        const POLE_WIDTH: Pixels = px(2.);
 7660
 7661        let line_layout =
 7662            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 7663        let target_column = target_display_point.column() as usize;
 7664
 7665        let target_x = line_layout.x_for_index(target_column);
 7666        let target_y =
 7667            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 7668
 7669        let flag_on_right = target_x < text_bounds.size.width / 2.;
 7670
 7671        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 7672        border_color.l += 0.001;
 7673
 7674        let mut element = v_flex()
 7675            .items_end()
 7676            .when(flag_on_right, |el| el.items_start())
 7677            .child(if flag_on_right {
 7678                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7679                    .rounded_bl(px(0.))
 7680                    .rounded_tl(px(0.))
 7681                    .border_l_2()
 7682                    .border_color(border_color)
 7683            } else {
 7684                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7685                    .rounded_br(px(0.))
 7686                    .rounded_tr(px(0.))
 7687                    .border_r_2()
 7688                    .border_color(border_color)
 7689            })
 7690            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 7691            .into_any();
 7692
 7693        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7694
 7695        let mut origin = scrolled_content_origin + point(target_x, target_y)
 7696            - point(
 7697                if flag_on_right {
 7698                    POLE_WIDTH
 7699                } else {
 7700                    size.width - POLE_WIDTH
 7701                },
 7702                size.height - line_height,
 7703            );
 7704
 7705        origin.x = origin.x.max(content_origin.x);
 7706
 7707        element.prepaint_at(origin, window, cx);
 7708
 7709        Some((element, origin))
 7710    }
 7711
 7712    fn render_edit_prediction_scroll_popover(
 7713        &mut self,
 7714        to_y: impl Fn(Size<Pixels>) -> Pixels,
 7715        scroll_icon: IconName,
 7716        visible_row_range: Range<DisplayRow>,
 7717        line_layouts: &[LineWithInvisibles],
 7718        newest_selection_head: Option<DisplayPoint>,
 7719        scrolled_content_origin: gpui::Point<Pixels>,
 7720        window: &mut Window,
 7721        cx: &mut App,
 7722    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7723        let mut element = self
 7724            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 7725            .into_any();
 7726
 7727        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7728
 7729        let cursor = newest_selection_head?;
 7730        let cursor_row_layout =
 7731            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 7732        let cursor_column = cursor.column() as usize;
 7733
 7734        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 7735
 7736        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 7737
 7738        element.prepaint_at(origin, window, cx);
 7739        Some((element, origin))
 7740    }
 7741
 7742    fn render_edit_prediction_eager_jump_popover(
 7743        &mut self,
 7744        text_bounds: &Bounds<Pixels>,
 7745        content_origin: gpui::Point<Pixels>,
 7746        editor_snapshot: &EditorSnapshot,
 7747        visible_row_range: Range<DisplayRow>,
 7748        scroll_top: f32,
 7749        scroll_bottom: f32,
 7750        line_height: Pixels,
 7751        scroll_pixel_position: gpui::Point<Pixels>,
 7752        target_display_point: DisplayPoint,
 7753        editor_width: Pixels,
 7754        window: &mut Window,
 7755        cx: &mut App,
 7756    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7757        if target_display_point.row().as_f32() < scroll_top {
 7758            let mut element = self
 7759                .render_edit_prediction_line_popover(
 7760                    "Jump to Edit",
 7761                    Some(IconName::ArrowUp),
 7762                    window,
 7763                    cx,
 7764                )?
 7765                .into_any();
 7766
 7767            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7768            let offset = point(
 7769                (text_bounds.size.width - size.width) / 2.,
 7770                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7771            );
 7772
 7773            let origin = text_bounds.origin + offset;
 7774            element.prepaint_at(origin, window, cx);
 7775            Some((element, origin))
 7776        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 7777            let mut element = self
 7778                .render_edit_prediction_line_popover(
 7779                    "Jump to Edit",
 7780                    Some(IconName::ArrowDown),
 7781                    window,
 7782                    cx,
 7783                )?
 7784                .into_any();
 7785
 7786            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7787            let offset = point(
 7788                (text_bounds.size.width - size.width) / 2.,
 7789                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7790            );
 7791
 7792            let origin = text_bounds.origin + offset;
 7793            element.prepaint_at(origin, window, cx);
 7794            Some((element, origin))
 7795        } else {
 7796            self.render_edit_prediction_end_of_line_popover(
 7797                "Jump to Edit",
 7798                editor_snapshot,
 7799                visible_row_range,
 7800                target_display_point,
 7801                line_height,
 7802                scroll_pixel_position,
 7803                content_origin,
 7804                editor_width,
 7805                window,
 7806                cx,
 7807            )
 7808        }
 7809    }
 7810
 7811    fn render_edit_prediction_end_of_line_popover(
 7812        self: &mut Editor,
 7813        label: &'static str,
 7814        editor_snapshot: &EditorSnapshot,
 7815        visible_row_range: Range<DisplayRow>,
 7816        target_display_point: DisplayPoint,
 7817        line_height: Pixels,
 7818        scroll_pixel_position: gpui::Point<Pixels>,
 7819        content_origin: gpui::Point<Pixels>,
 7820        editor_width: Pixels,
 7821        window: &mut Window,
 7822        cx: &mut App,
 7823    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7824        let target_line_end = DisplayPoint::new(
 7825            target_display_point.row(),
 7826            editor_snapshot.line_len(target_display_point.row()),
 7827        );
 7828
 7829        let mut element = self
 7830            .render_edit_prediction_line_popover(label, None, window, cx)?
 7831            .into_any();
 7832
 7833        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7834
 7835        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 7836
 7837        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 7838        let mut origin = start_point
 7839            + line_origin
 7840            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 7841        origin.x = origin.x.max(content_origin.x);
 7842
 7843        let max_x = content_origin.x + editor_width - size.width;
 7844
 7845        if origin.x > max_x {
 7846            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 7847
 7848            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 7849                origin.y += offset;
 7850                IconName::ArrowUp
 7851            } else {
 7852                origin.y -= offset;
 7853                IconName::ArrowDown
 7854            };
 7855
 7856            element = self
 7857                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 7858                .into_any();
 7859
 7860            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7861
 7862            origin.x = content_origin.x + editor_width - size.width - px(2.);
 7863        }
 7864
 7865        element.prepaint_at(origin, window, cx);
 7866        Some((element, origin))
 7867    }
 7868
 7869    fn render_edit_prediction_diff_popover(
 7870        self: &Editor,
 7871        text_bounds: &Bounds<Pixels>,
 7872        content_origin: gpui::Point<Pixels>,
 7873        right_margin: Pixels,
 7874        editor_snapshot: &EditorSnapshot,
 7875        visible_row_range: Range<DisplayRow>,
 7876        line_layouts: &[LineWithInvisibles],
 7877        line_height: Pixels,
 7878        scroll_pixel_position: gpui::Point<Pixels>,
 7879        newest_selection_head: Option<DisplayPoint>,
 7880        editor_width: Pixels,
 7881        style: &EditorStyle,
 7882        edits: &Vec<(Range<Anchor>, String)>,
 7883        edit_preview: &Option<language::EditPreview>,
 7884        snapshot: &language::BufferSnapshot,
 7885        window: &mut Window,
 7886        cx: &mut App,
 7887    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7888        let edit_start = edits
 7889            .first()
 7890            .unwrap()
 7891            .0
 7892            .start
 7893            .to_display_point(editor_snapshot);
 7894        let edit_end = edits
 7895            .last()
 7896            .unwrap()
 7897            .0
 7898            .end
 7899            .to_display_point(editor_snapshot);
 7900
 7901        let is_visible = visible_row_range.contains(&edit_start.row())
 7902            || visible_row_range.contains(&edit_end.row());
 7903        if !is_visible {
 7904            return None;
 7905        }
 7906
 7907        let highlighted_edits =
 7908            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 7909
 7910        let styled_text = highlighted_edits.to_styled_text(&style.text);
 7911        let line_count = highlighted_edits.text.lines().count();
 7912
 7913        const BORDER_WIDTH: Pixels = px(1.);
 7914
 7915        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 7916        let has_keybind = keybind.is_some();
 7917
 7918        let mut element = h_flex()
 7919            .items_start()
 7920            .child(
 7921                h_flex()
 7922                    .bg(cx.theme().colors().editor_background)
 7923                    .border(BORDER_WIDTH)
 7924                    .shadow_sm()
 7925                    .border_color(cx.theme().colors().border)
 7926                    .rounded_l_lg()
 7927                    .when(line_count > 1, |el| el.rounded_br_lg())
 7928                    .pr_1()
 7929                    .child(styled_text),
 7930            )
 7931            .child(
 7932                h_flex()
 7933                    .h(line_height + BORDER_WIDTH * 2.)
 7934                    .px_1p5()
 7935                    .gap_1()
 7936                    // Workaround: For some reason, there's a gap if we don't do this
 7937                    .ml(-BORDER_WIDTH)
 7938                    .shadow(smallvec![gpui::BoxShadow {
 7939                        color: gpui::black().opacity(0.05),
 7940                        offset: point(px(1.), px(1.)),
 7941                        blur_radius: px(2.),
 7942                        spread_radius: px(0.),
 7943                    }])
 7944                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 7945                    .border(BORDER_WIDTH)
 7946                    .border_color(cx.theme().colors().border)
 7947                    .rounded_r_lg()
 7948                    .id("edit_prediction_diff_popover_keybind")
 7949                    .when(!has_keybind, |el| {
 7950                        let status_colors = cx.theme().status();
 7951
 7952                        el.bg(status_colors.error_background)
 7953                            .border_color(status_colors.error.opacity(0.6))
 7954                            .child(Icon::new(IconName::Info).color(Color::Error))
 7955                            .cursor_default()
 7956                            .hoverable_tooltip(move |_window, cx| {
 7957                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 7958                            })
 7959                    })
 7960                    .children(keybind),
 7961            )
 7962            .into_any();
 7963
 7964        let longest_row =
 7965            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 7966        let longest_line_width = if visible_row_range.contains(&longest_row) {
 7967            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 7968        } else {
 7969            layout_line(
 7970                longest_row,
 7971                editor_snapshot,
 7972                style,
 7973                editor_width,
 7974                |_| false,
 7975                window,
 7976                cx,
 7977            )
 7978            .width
 7979        };
 7980
 7981        let viewport_bounds =
 7982            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 7983                right: -right_margin,
 7984                ..Default::default()
 7985            });
 7986
 7987        let x_after_longest =
 7988            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 7989                - scroll_pixel_position.x;
 7990
 7991        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7992
 7993        // Fully visible if it can be displayed within the window (allow overlapping other
 7994        // panes). However, this is only allowed if the popover starts within text_bounds.
 7995        let can_position_to_the_right = x_after_longest < text_bounds.right()
 7996            && x_after_longest + element_bounds.width < viewport_bounds.right();
 7997
 7998        let mut origin = if can_position_to_the_right {
 7999            point(
 8000                x_after_longest,
 8001                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8002                    - scroll_pixel_position.y,
 8003            )
 8004        } else {
 8005            let cursor_row = newest_selection_head.map(|head| head.row());
 8006            let above_edit = edit_start
 8007                .row()
 8008                .0
 8009                .checked_sub(line_count as u32)
 8010                .map(DisplayRow);
 8011            let below_edit = Some(edit_end.row() + 1);
 8012            let above_cursor =
 8013                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8014            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8015
 8016            // Place the edit popover adjacent to the edit if there is a location
 8017            // available that is onscreen and does not obscure the cursor. Otherwise,
 8018            // place it adjacent to the cursor.
 8019            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8020                .into_iter()
 8021                .flatten()
 8022                .find(|&start_row| {
 8023                    let end_row = start_row + line_count as u32;
 8024                    visible_row_range.contains(&start_row)
 8025                        && visible_row_range.contains(&end_row)
 8026                        && cursor_row.map_or(true, |cursor_row| {
 8027                            !((start_row..end_row).contains(&cursor_row))
 8028                        })
 8029                })?;
 8030
 8031            content_origin
 8032                + point(
 8033                    -scroll_pixel_position.x,
 8034                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8035                )
 8036        };
 8037
 8038        origin.x -= BORDER_WIDTH;
 8039
 8040        window.defer_draw(element, origin, 1);
 8041
 8042        // Do not return an element, since it will already be drawn due to defer_draw.
 8043        None
 8044    }
 8045
 8046    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8047        px(30.)
 8048    }
 8049
 8050    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8051        if self.read_only(cx) {
 8052            cx.theme().players().read_only()
 8053        } else {
 8054            self.style.as_ref().unwrap().local_player
 8055        }
 8056    }
 8057
 8058    fn render_edit_prediction_accept_keybind(
 8059        &self,
 8060        window: &mut Window,
 8061        cx: &App,
 8062    ) -> Option<AnyElement> {
 8063        let accept_binding = self.accept_edit_prediction_keybind(window, cx);
 8064        let accept_keystroke = accept_binding.keystroke()?;
 8065
 8066        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8067
 8068        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8069            Color::Accent
 8070        } else {
 8071            Color::Muted
 8072        };
 8073
 8074        h_flex()
 8075            .px_0p5()
 8076            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8077            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8078            .text_size(TextSize::XSmall.rems(cx))
 8079            .child(h_flex().children(ui::render_modifiers(
 8080                &accept_keystroke.modifiers,
 8081                PlatformStyle::platform(),
 8082                Some(modifiers_color),
 8083                Some(IconSize::XSmall.rems().into()),
 8084                true,
 8085            )))
 8086            .when(is_platform_style_mac, |parent| {
 8087                parent.child(accept_keystroke.key.clone())
 8088            })
 8089            .when(!is_platform_style_mac, |parent| {
 8090                parent.child(
 8091                    Key::new(
 8092                        util::capitalize(&accept_keystroke.key),
 8093                        Some(Color::Default),
 8094                    )
 8095                    .size(Some(IconSize::XSmall.rems().into())),
 8096                )
 8097            })
 8098            .into_any()
 8099            .into()
 8100    }
 8101
 8102    fn render_edit_prediction_line_popover(
 8103        &self,
 8104        label: impl Into<SharedString>,
 8105        icon: Option<IconName>,
 8106        window: &mut Window,
 8107        cx: &App,
 8108    ) -> Option<Stateful<Div>> {
 8109        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8110
 8111        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8112        let has_keybind = keybind.is_some();
 8113
 8114        let result = h_flex()
 8115            .id("ep-line-popover")
 8116            .py_0p5()
 8117            .pl_1()
 8118            .pr(padding_right)
 8119            .gap_1()
 8120            .rounded_md()
 8121            .border_1()
 8122            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8123            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8124            .shadow_sm()
 8125            .when(!has_keybind, |el| {
 8126                let status_colors = cx.theme().status();
 8127
 8128                el.bg(status_colors.error_background)
 8129                    .border_color(status_colors.error.opacity(0.6))
 8130                    .pl_2()
 8131                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8132                    .cursor_default()
 8133                    .hoverable_tooltip(move |_window, cx| {
 8134                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8135                    })
 8136            })
 8137            .children(keybind)
 8138            .child(
 8139                Label::new(label)
 8140                    .size(LabelSize::Small)
 8141                    .when(!has_keybind, |el| {
 8142                        el.color(cx.theme().status().error.into()).strikethrough()
 8143                    }),
 8144            )
 8145            .when(!has_keybind, |el| {
 8146                el.child(
 8147                    h_flex().ml_1().child(
 8148                        Icon::new(IconName::Info)
 8149                            .size(IconSize::Small)
 8150                            .color(cx.theme().status().error.into()),
 8151                    ),
 8152                )
 8153            })
 8154            .when_some(icon, |element, icon| {
 8155                element.child(
 8156                    div()
 8157                        .mt(px(1.5))
 8158                        .child(Icon::new(icon).size(IconSize::Small)),
 8159                )
 8160            });
 8161
 8162        Some(result)
 8163    }
 8164
 8165    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8166        let accent_color = cx.theme().colors().text_accent;
 8167        let editor_bg_color = cx.theme().colors().editor_background;
 8168        editor_bg_color.blend(accent_color.opacity(0.1))
 8169    }
 8170
 8171    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8172        let accent_color = cx.theme().colors().text_accent;
 8173        let editor_bg_color = cx.theme().colors().editor_background;
 8174        editor_bg_color.blend(accent_color.opacity(0.6))
 8175    }
 8176
 8177    fn render_edit_prediction_cursor_popover(
 8178        &self,
 8179        min_width: Pixels,
 8180        max_width: Pixels,
 8181        cursor_point: Point,
 8182        style: &EditorStyle,
 8183        accept_keystroke: Option<&gpui::Keystroke>,
 8184        _window: &Window,
 8185        cx: &mut Context<Editor>,
 8186    ) -> Option<AnyElement> {
 8187        let provider = self.edit_prediction_provider.as_ref()?;
 8188
 8189        if provider.provider.needs_terms_acceptance(cx) {
 8190            return Some(
 8191                h_flex()
 8192                    .min_w(min_width)
 8193                    .flex_1()
 8194                    .px_2()
 8195                    .py_1()
 8196                    .gap_3()
 8197                    .elevation_2(cx)
 8198                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8199                    .id("accept-terms")
 8200                    .cursor_pointer()
 8201                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8202                    .on_click(cx.listener(|this, _event, window, cx| {
 8203                        cx.stop_propagation();
 8204                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8205                        window.dispatch_action(
 8206                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8207                            cx,
 8208                        );
 8209                    }))
 8210                    .child(
 8211                        h_flex()
 8212                            .flex_1()
 8213                            .gap_2()
 8214                            .child(Icon::new(IconName::ZedPredict))
 8215                            .child(Label::new("Accept Terms of Service"))
 8216                            .child(div().w_full())
 8217                            .child(
 8218                                Icon::new(IconName::ArrowUpRight)
 8219                                    .color(Color::Muted)
 8220                                    .size(IconSize::Small),
 8221                            )
 8222                            .into_any_element(),
 8223                    )
 8224                    .into_any(),
 8225            );
 8226        }
 8227
 8228        let is_refreshing = provider.provider.is_refreshing(cx);
 8229
 8230        fn pending_completion_container() -> Div {
 8231            h_flex()
 8232                .h_full()
 8233                .flex_1()
 8234                .gap_2()
 8235                .child(Icon::new(IconName::ZedPredict))
 8236        }
 8237
 8238        let completion = match &self.active_inline_completion {
 8239            Some(prediction) => {
 8240                if !self.has_visible_completions_menu() {
 8241                    const RADIUS: Pixels = px(6.);
 8242                    const BORDER_WIDTH: Pixels = px(1.);
 8243
 8244                    return Some(
 8245                        h_flex()
 8246                            .elevation_2(cx)
 8247                            .border(BORDER_WIDTH)
 8248                            .border_color(cx.theme().colors().border)
 8249                            .when(accept_keystroke.is_none(), |el| {
 8250                                el.border_color(cx.theme().status().error)
 8251                            })
 8252                            .rounded(RADIUS)
 8253                            .rounded_tl(px(0.))
 8254                            .overflow_hidden()
 8255                            .child(div().px_1p5().child(match &prediction.completion {
 8256                                InlineCompletion::Move { target, snapshot } => {
 8257                                    use text::ToPoint as _;
 8258                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8259                                    {
 8260                                        Icon::new(IconName::ZedPredictDown)
 8261                                    } else {
 8262                                        Icon::new(IconName::ZedPredictUp)
 8263                                    }
 8264                                }
 8265                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8266                            }))
 8267                            .child(
 8268                                h_flex()
 8269                                    .gap_1()
 8270                                    .py_1()
 8271                                    .px_2()
 8272                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8273                                    .border_l_1()
 8274                                    .border_color(cx.theme().colors().border)
 8275                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8276                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8277                                        el.child(
 8278                                            Label::new("Hold")
 8279                                                .size(LabelSize::Small)
 8280                                                .when(accept_keystroke.is_none(), |el| {
 8281                                                    el.strikethrough()
 8282                                                })
 8283                                                .line_height_style(LineHeightStyle::UiLabel),
 8284                                        )
 8285                                    })
 8286                                    .id("edit_prediction_cursor_popover_keybind")
 8287                                    .when(accept_keystroke.is_none(), |el| {
 8288                                        let status_colors = cx.theme().status();
 8289
 8290                                        el.bg(status_colors.error_background)
 8291                                            .border_color(status_colors.error.opacity(0.6))
 8292                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8293                                            .cursor_default()
 8294                                            .hoverable_tooltip(move |_window, cx| {
 8295                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8296                                                    .into()
 8297                                            })
 8298                                    })
 8299                                    .when_some(
 8300                                        accept_keystroke.as_ref(),
 8301                                        |el, accept_keystroke| {
 8302                                            el.child(h_flex().children(ui::render_modifiers(
 8303                                                &accept_keystroke.modifiers,
 8304                                                PlatformStyle::platform(),
 8305                                                Some(Color::Default),
 8306                                                Some(IconSize::XSmall.rems().into()),
 8307                                                false,
 8308                                            )))
 8309                                        },
 8310                                    ),
 8311                            )
 8312                            .into_any(),
 8313                    );
 8314                }
 8315
 8316                self.render_edit_prediction_cursor_popover_preview(
 8317                    prediction,
 8318                    cursor_point,
 8319                    style,
 8320                    cx,
 8321                )?
 8322            }
 8323
 8324            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8325                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8326                    stale_completion,
 8327                    cursor_point,
 8328                    style,
 8329                    cx,
 8330                )?,
 8331
 8332                None => {
 8333                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8334                }
 8335            },
 8336
 8337            None => pending_completion_container().child(Label::new("No Prediction")),
 8338        };
 8339
 8340        let completion = if is_refreshing {
 8341            completion
 8342                .with_animation(
 8343                    "loading-completion",
 8344                    Animation::new(Duration::from_secs(2))
 8345                        .repeat()
 8346                        .with_easing(pulsating_between(0.4, 0.8)),
 8347                    |label, delta| label.opacity(delta),
 8348                )
 8349                .into_any_element()
 8350        } else {
 8351            completion.into_any_element()
 8352        };
 8353
 8354        let has_completion = self.active_inline_completion.is_some();
 8355
 8356        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8357        Some(
 8358            h_flex()
 8359                .min_w(min_width)
 8360                .max_w(max_width)
 8361                .flex_1()
 8362                .elevation_2(cx)
 8363                .border_color(cx.theme().colors().border)
 8364                .child(
 8365                    div()
 8366                        .flex_1()
 8367                        .py_1()
 8368                        .px_2()
 8369                        .overflow_hidden()
 8370                        .child(completion),
 8371                )
 8372                .when_some(accept_keystroke, |el, accept_keystroke| {
 8373                    if !accept_keystroke.modifiers.modified() {
 8374                        return el;
 8375                    }
 8376
 8377                    el.child(
 8378                        h_flex()
 8379                            .h_full()
 8380                            .border_l_1()
 8381                            .rounded_r_lg()
 8382                            .border_color(cx.theme().colors().border)
 8383                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8384                            .gap_1()
 8385                            .py_1()
 8386                            .px_2()
 8387                            .child(
 8388                                h_flex()
 8389                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8390                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8391                                    .child(h_flex().children(ui::render_modifiers(
 8392                                        &accept_keystroke.modifiers,
 8393                                        PlatformStyle::platform(),
 8394                                        Some(if !has_completion {
 8395                                            Color::Muted
 8396                                        } else {
 8397                                            Color::Default
 8398                                        }),
 8399                                        None,
 8400                                        false,
 8401                                    ))),
 8402                            )
 8403                            .child(Label::new("Preview").into_any_element())
 8404                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8405                    )
 8406                })
 8407                .into_any(),
 8408        )
 8409    }
 8410
 8411    fn render_edit_prediction_cursor_popover_preview(
 8412        &self,
 8413        completion: &InlineCompletionState,
 8414        cursor_point: Point,
 8415        style: &EditorStyle,
 8416        cx: &mut Context<Editor>,
 8417    ) -> Option<Div> {
 8418        use text::ToPoint as _;
 8419
 8420        fn render_relative_row_jump(
 8421            prefix: impl Into<String>,
 8422            current_row: u32,
 8423            target_row: u32,
 8424        ) -> Div {
 8425            let (row_diff, arrow) = if target_row < current_row {
 8426                (current_row - target_row, IconName::ArrowUp)
 8427            } else {
 8428                (target_row - current_row, IconName::ArrowDown)
 8429            };
 8430
 8431            h_flex()
 8432                .child(
 8433                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8434                        .color(Color::Muted)
 8435                        .size(LabelSize::Small),
 8436                )
 8437                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8438        }
 8439
 8440        match &completion.completion {
 8441            InlineCompletion::Move {
 8442                target, snapshot, ..
 8443            } => Some(
 8444                h_flex()
 8445                    .px_2()
 8446                    .gap_2()
 8447                    .flex_1()
 8448                    .child(
 8449                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8450                            Icon::new(IconName::ZedPredictDown)
 8451                        } else {
 8452                            Icon::new(IconName::ZedPredictUp)
 8453                        },
 8454                    )
 8455                    .child(Label::new("Jump to Edit")),
 8456            ),
 8457
 8458            InlineCompletion::Edit {
 8459                edits,
 8460                edit_preview,
 8461                snapshot,
 8462                display_mode: _,
 8463            } => {
 8464                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8465
 8466                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8467                    &snapshot,
 8468                    &edits,
 8469                    edit_preview.as_ref()?,
 8470                    true,
 8471                    cx,
 8472                )
 8473                .first_line_preview();
 8474
 8475                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8476                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8477
 8478                let preview = h_flex()
 8479                    .gap_1()
 8480                    .min_w_16()
 8481                    .child(styled_text)
 8482                    .when(has_more_lines, |parent| parent.child(""));
 8483
 8484                let left = if first_edit_row != cursor_point.row {
 8485                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8486                        .into_any_element()
 8487                } else {
 8488                    Icon::new(IconName::ZedPredict).into_any_element()
 8489                };
 8490
 8491                Some(
 8492                    h_flex()
 8493                        .h_full()
 8494                        .flex_1()
 8495                        .gap_2()
 8496                        .pr_1()
 8497                        .overflow_x_hidden()
 8498                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8499                        .child(left)
 8500                        .child(preview),
 8501                )
 8502            }
 8503        }
 8504    }
 8505
 8506    fn render_context_menu(
 8507        &self,
 8508        style: &EditorStyle,
 8509        max_height_in_lines: u32,
 8510        window: &mut Window,
 8511        cx: &mut Context<Editor>,
 8512    ) -> Option<AnyElement> {
 8513        let menu = self.context_menu.borrow();
 8514        let menu = menu.as_ref()?;
 8515        if !menu.visible() {
 8516            return None;
 8517        };
 8518        Some(menu.render(style, max_height_in_lines, window, cx))
 8519    }
 8520
 8521    fn render_context_menu_aside(
 8522        &mut self,
 8523        max_size: Size<Pixels>,
 8524        window: &mut Window,
 8525        cx: &mut Context<Editor>,
 8526    ) -> Option<AnyElement> {
 8527        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 8528            if menu.visible() {
 8529                menu.render_aside(self, max_size, window, cx)
 8530            } else {
 8531                None
 8532            }
 8533        })
 8534    }
 8535
 8536    fn hide_context_menu(
 8537        &mut self,
 8538        window: &mut Window,
 8539        cx: &mut Context<Self>,
 8540    ) -> Option<CodeContextMenu> {
 8541        cx.notify();
 8542        self.completion_tasks.clear();
 8543        let context_menu = self.context_menu.borrow_mut().take();
 8544        self.stale_inline_completion_in_menu.take();
 8545        self.update_visible_inline_completion(window, cx);
 8546        context_menu
 8547    }
 8548
 8549    fn show_snippet_choices(
 8550        &mut self,
 8551        choices: &Vec<String>,
 8552        selection: Range<Anchor>,
 8553        cx: &mut Context<Self>,
 8554    ) {
 8555        if selection.start.buffer_id.is_none() {
 8556            return;
 8557        }
 8558        let buffer_id = selection.start.buffer_id.unwrap();
 8559        let buffer = self.buffer().read(cx).buffer(buffer_id);
 8560        let id = post_inc(&mut self.next_completion_id);
 8561        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 8562
 8563        if let Some(buffer) = buffer {
 8564            *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 8565                CompletionsMenu::new_snippet_choices(
 8566                    id,
 8567                    true,
 8568                    choices,
 8569                    selection,
 8570                    buffer,
 8571                    snippet_sort_order,
 8572                ),
 8573            ));
 8574        }
 8575    }
 8576
 8577    pub fn insert_snippet(
 8578        &mut self,
 8579        insertion_ranges: &[Range<usize>],
 8580        snippet: Snippet,
 8581        window: &mut Window,
 8582        cx: &mut Context<Self>,
 8583    ) -> Result<()> {
 8584        struct Tabstop<T> {
 8585            is_end_tabstop: bool,
 8586            ranges: Vec<Range<T>>,
 8587            choices: Option<Vec<String>>,
 8588        }
 8589
 8590        let tabstops = self.buffer.update(cx, |buffer, cx| {
 8591            let snippet_text: Arc<str> = snippet.text.clone().into();
 8592            let edits = insertion_ranges
 8593                .iter()
 8594                .cloned()
 8595                .map(|range| (range, snippet_text.clone()));
 8596            buffer.edit(edits, Some(AutoindentMode::EachLine), cx);
 8597
 8598            let snapshot = &*buffer.read(cx);
 8599            let snippet = &snippet;
 8600            snippet
 8601                .tabstops
 8602                .iter()
 8603                .map(|tabstop| {
 8604                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 8605                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 8606                    });
 8607                    let mut tabstop_ranges = tabstop
 8608                        .ranges
 8609                        .iter()
 8610                        .flat_map(|tabstop_range| {
 8611                            let mut delta = 0_isize;
 8612                            insertion_ranges.iter().map(move |insertion_range| {
 8613                                let insertion_start = insertion_range.start as isize + delta;
 8614                                delta +=
 8615                                    snippet.text.len() as isize - insertion_range.len() as isize;
 8616
 8617                                let start = ((insertion_start + tabstop_range.start) as usize)
 8618                                    .min(snapshot.len());
 8619                                let end = ((insertion_start + tabstop_range.end) as usize)
 8620                                    .min(snapshot.len());
 8621                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 8622                            })
 8623                        })
 8624                        .collect::<Vec<_>>();
 8625                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 8626
 8627                    Tabstop {
 8628                        is_end_tabstop,
 8629                        ranges: tabstop_ranges,
 8630                        choices: tabstop.choices.clone(),
 8631                    }
 8632                })
 8633                .collect::<Vec<_>>()
 8634        });
 8635        if let Some(tabstop) = tabstops.first() {
 8636            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8637                s.select_ranges(tabstop.ranges.iter().cloned());
 8638            });
 8639
 8640            if let Some(choices) = &tabstop.choices {
 8641                if let Some(selection) = tabstop.ranges.first() {
 8642                    self.show_snippet_choices(choices, selection.clone(), cx)
 8643                }
 8644            }
 8645
 8646            // If we're already at the last tabstop and it's at the end of the snippet,
 8647            // we're done, we don't need to keep the state around.
 8648            if !tabstop.is_end_tabstop {
 8649                let choices = tabstops
 8650                    .iter()
 8651                    .map(|tabstop| tabstop.choices.clone())
 8652                    .collect();
 8653
 8654                let ranges = tabstops
 8655                    .into_iter()
 8656                    .map(|tabstop| tabstop.ranges)
 8657                    .collect::<Vec<_>>();
 8658
 8659                self.snippet_stack.push(SnippetState {
 8660                    active_index: 0,
 8661                    ranges,
 8662                    choices,
 8663                });
 8664            }
 8665
 8666            // Check whether the just-entered snippet ends with an auto-closable bracket.
 8667            if self.autoclose_regions.is_empty() {
 8668                let snapshot = self.buffer.read(cx).snapshot(cx);
 8669                for selection in &mut self.selections.all::<Point>(cx) {
 8670                    let selection_head = selection.head();
 8671                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 8672                        continue;
 8673                    };
 8674
 8675                    let mut bracket_pair = None;
 8676                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 8677                    let prev_chars = snapshot
 8678                        .reversed_chars_at(selection_head)
 8679                        .collect::<String>();
 8680                    for (pair, enabled) in scope.brackets() {
 8681                        if enabled
 8682                            && pair.close
 8683                            && prev_chars.starts_with(pair.start.as_str())
 8684                            && next_chars.starts_with(pair.end.as_str())
 8685                        {
 8686                            bracket_pair = Some(pair.clone());
 8687                            break;
 8688                        }
 8689                    }
 8690                    if let Some(pair) = bracket_pair {
 8691                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 8692                        let autoclose_enabled =
 8693                            self.use_autoclose && snapshot_settings.use_autoclose;
 8694                        if autoclose_enabled {
 8695                            let start = snapshot.anchor_after(selection_head);
 8696                            let end = snapshot.anchor_after(selection_head);
 8697                            self.autoclose_regions.push(AutocloseRegion {
 8698                                selection_id: selection.id,
 8699                                range: start..end,
 8700                                pair,
 8701                            });
 8702                        }
 8703                    }
 8704                }
 8705            }
 8706        }
 8707        Ok(())
 8708    }
 8709
 8710    pub fn move_to_next_snippet_tabstop(
 8711        &mut self,
 8712        window: &mut Window,
 8713        cx: &mut Context<Self>,
 8714    ) -> bool {
 8715        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 8716    }
 8717
 8718    pub fn move_to_prev_snippet_tabstop(
 8719        &mut self,
 8720        window: &mut Window,
 8721        cx: &mut Context<Self>,
 8722    ) -> bool {
 8723        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 8724    }
 8725
 8726    pub fn move_to_snippet_tabstop(
 8727        &mut self,
 8728        bias: Bias,
 8729        window: &mut Window,
 8730        cx: &mut Context<Self>,
 8731    ) -> bool {
 8732        if let Some(mut snippet) = self.snippet_stack.pop() {
 8733            match bias {
 8734                Bias::Left => {
 8735                    if snippet.active_index > 0 {
 8736                        snippet.active_index -= 1;
 8737                    } else {
 8738                        self.snippet_stack.push(snippet);
 8739                        return false;
 8740                    }
 8741                }
 8742                Bias::Right => {
 8743                    if snippet.active_index + 1 < snippet.ranges.len() {
 8744                        snippet.active_index += 1;
 8745                    } else {
 8746                        self.snippet_stack.push(snippet);
 8747                        return false;
 8748                    }
 8749                }
 8750            }
 8751            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 8752                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8753                    s.select_anchor_ranges(current_ranges.iter().cloned())
 8754                });
 8755
 8756                if let Some(choices) = &snippet.choices[snippet.active_index] {
 8757                    if let Some(selection) = current_ranges.first() {
 8758                        self.show_snippet_choices(&choices, selection.clone(), cx);
 8759                    }
 8760                }
 8761
 8762                // If snippet state is not at the last tabstop, push it back on the stack
 8763                if snippet.active_index + 1 < snippet.ranges.len() {
 8764                    self.snippet_stack.push(snippet);
 8765                }
 8766                return true;
 8767            }
 8768        }
 8769
 8770        false
 8771    }
 8772
 8773    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 8774        self.transact(window, cx, |this, window, cx| {
 8775            this.select_all(&SelectAll, window, cx);
 8776            this.insert("", window, cx);
 8777        });
 8778    }
 8779
 8780    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 8781        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8782        self.transact(window, cx, |this, window, cx| {
 8783            this.select_autoclose_pair(window, cx);
 8784            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 8785            if !this.linked_edit_ranges.is_empty() {
 8786                let selections = this.selections.all::<MultiBufferPoint>(cx);
 8787                let snapshot = this.buffer.read(cx).snapshot(cx);
 8788
 8789                for selection in selections.iter() {
 8790                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 8791                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 8792                    if selection_start.buffer_id != selection_end.buffer_id {
 8793                        continue;
 8794                    }
 8795                    if let Some(ranges) =
 8796                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 8797                    {
 8798                        for (buffer, entries) in ranges {
 8799                            linked_ranges.entry(buffer).or_default().extend(entries);
 8800                        }
 8801                    }
 8802                }
 8803            }
 8804
 8805            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 8806            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 8807            for selection in &mut selections {
 8808                if selection.is_empty() {
 8809                    let old_head = selection.head();
 8810                    let mut new_head =
 8811                        movement::left(&display_map, old_head.to_display_point(&display_map))
 8812                            .to_point(&display_map);
 8813                    if let Some((buffer, line_buffer_range)) = display_map
 8814                        .buffer_snapshot
 8815                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 8816                    {
 8817                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 8818                        let indent_len = match indent_size.kind {
 8819                            IndentKind::Space => {
 8820                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 8821                            }
 8822                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 8823                        };
 8824                        if old_head.column <= indent_size.len && old_head.column > 0 {
 8825                            let indent_len = indent_len.get();
 8826                            new_head = cmp::min(
 8827                                new_head,
 8828                                MultiBufferPoint::new(
 8829                                    old_head.row,
 8830                                    ((old_head.column - 1) / indent_len) * indent_len,
 8831                                ),
 8832                            );
 8833                        }
 8834                    }
 8835
 8836                    selection.set_head(new_head, SelectionGoal::None);
 8837                }
 8838            }
 8839
 8840            this.signature_help_state.set_backspace_pressed(true);
 8841            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8842                s.select(selections)
 8843            });
 8844            this.insert("", window, cx);
 8845            let empty_str: Arc<str> = Arc::from("");
 8846            for (buffer, edits) in linked_ranges {
 8847                let snapshot = buffer.read(cx).snapshot();
 8848                use text::ToPoint as TP;
 8849
 8850                let edits = edits
 8851                    .into_iter()
 8852                    .map(|range| {
 8853                        let end_point = TP::to_point(&range.end, &snapshot);
 8854                        let mut start_point = TP::to_point(&range.start, &snapshot);
 8855
 8856                        if end_point == start_point {
 8857                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 8858                                .saturating_sub(1);
 8859                            start_point =
 8860                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 8861                        };
 8862
 8863                        (start_point..end_point, empty_str.clone())
 8864                    })
 8865                    .sorted_by_key(|(range, _)| range.start)
 8866                    .collect::<Vec<_>>();
 8867                buffer.update(cx, |this, cx| {
 8868                    this.edit(edits, None, cx);
 8869                })
 8870            }
 8871            this.refresh_inline_completion(true, false, window, cx);
 8872            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 8873        });
 8874    }
 8875
 8876    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 8877        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8878        self.transact(window, cx, |this, window, cx| {
 8879            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8880                s.move_with(|map, selection| {
 8881                    if selection.is_empty() {
 8882                        let cursor = movement::right(map, selection.head());
 8883                        selection.end = cursor;
 8884                        selection.reversed = true;
 8885                        selection.goal = SelectionGoal::None;
 8886                    }
 8887                })
 8888            });
 8889            this.insert("", window, cx);
 8890            this.refresh_inline_completion(true, false, window, cx);
 8891        });
 8892    }
 8893
 8894    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 8895        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8896        if self.move_to_prev_snippet_tabstop(window, cx) {
 8897            return;
 8898        }
 8899        self.outdent(&Outdent, window, cx);
 8900    }
 8901
 8902    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 8903        if self.move_to_next_snippet_tabstop(window, cx) {
 8904            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8905            return;
 8906        }
 8907        if self.read_only(cx) {
 8908            return;
 8909        }
 8910        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8911        let mut selections = self.selections.all_adjusted(cx);
 8912        let buffer = self.buffer.read(cx);
 8913        let snapshot = buffer.snapshot(cx);
 8914        let rows_iter = selections.iter().map(|s| s.head().row);
 8915        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 8916
 8917        let has_some_cursor_in_whitespace = selections
 8918            .iter()
 8919            .filter(|selection| selection.is_empty())
 8920            .any(|selection| {
 8921                let cursor = selection.head();
 8922                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 8923                cursor.column < current_indent.len
 8924            });
 8925
 8926        let mut edits = Vec::new();
 8927        let mut prev_edited_row = 0;
 8928        let mut row_delta = 0;
 8929        for selection in &mut selections {
 8930            if selection.start.row != prev_edited_row {
 8931                row_delta = 0;
 8932            }
 8933            prev_edited_row = selection.end.row;
 8934
 8935            // If the selection is non-empty, then increase the indentation of the selected lines.
 8936            if !selection.is_empty() {
 8937                row_delta =
 8938                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 8939                continue;
 8940            }
 8941
 8942            let cursor = selection.head();
 8943            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 8944            if let Some(suggested_indent) =
 8945                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 8946            {
 8947                // Don't do anything if already at suggested indent
 8948                // and there is any other cursor which is not
 8949                if has_some_cursor_in_whitespace
 8950                    && cursor.column == current_indent.len
 8951                    && current_indent.len == suggested_indent.len
 8952                {
 8953                    continue;
 8954                }
 8955
 8956                // Adjust line and move cursor to suggested indent
 8957                // if cursor is not at suggested indent
 8958                if cursor.column < suggested_indent.len
 8959                    && cursor.column <= current_indent.len
 8960                    && current_indent.len <= suggested_indent.len
 8961                {
 8962                    selection.start = Point::new(cursor.row, suggested_indent.len);
 8963                    selection.end = selection.start;
 8964                    if row_delta == 0 {
 8965                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 8966                            cursor.row,
 8967                            current_indent,
 8968                            suggested_indent,
 8969                        ));
 8970                        row_delta = suggested_indent.len - current_indent.len;
 8971                    }
 8972                    continue;
 8973                }
 8974
 8975                // If current indent is more than suggested indent
 8976                // only move cursor to current indent and skip indent
 8977                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 8978                    selection.start = Point::new(cursor.row, current_indent.len);
 8979                    selection.end = selection.start;
 8980                    continue;
 8981                }
 8982            }
 8983
 8984            // Otherwise, insert a hard or soft tab.
 8985            let settings = buffer.language_settings_at(cursor, cx);
 8986            let tab_size = if settings.hard_tabs {
 8987                IndentSize::tab()
 8988            } else {
 8989                let tab_size = settings.tab_size.get();
 8990                let indent_remainder = snapshot
 8991                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 8992                    .flat_map(str::chars)
 8993                    .fold(row_delta % tab_size, |counter: u32, c| {
 8994                        if c == '\t' {
 8995                            0
 8996                        } else {
 8997                            (counter + 1) % tab_size
 8998                        }
 8999                    });
 9000
 9001                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9002                IndentSize::spaces(chars_to_next_tab_stop)
 9003            };
 9004            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9005            selection.end = selection.start;
 9006            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9007            row_delta += tab_size.len;
 9008        }
 9009
 9010        self.transact(window, cx, |this, window, cx| {
 9011            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9012            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9013                s.select(selections)
 9014            });
 9015            this.refresh_inline_completion(true, false, window, cx);
 9016        });
 9017    }
 9018
 9019    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9020        if self.read_only(cx) {
 9021            return;
 9022        }
 9023        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9024        let mut selections = self.selections.all::<Point>(cx);
 9025        let mut prev_edited_row = 0;
 9026        let mut row_delta = 0;
 9027        let mut edits = Vec::new();
 9028        let buffer = self.buffer.read(cx);
 9029        let snapshot = buffer.snapshot(cx);
 9030        for selection in &mut selections {
 9031            if selection.start.row != prev_edited_row {
 9032                row_delta = 0;
 9033            }
 9034            prev_edited_row = selection.end.row;
 9035
 9036            row_delta =
 9037                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9038        }
 9039
 9040        self.transact(window, cx, |this, window, cx| {
 9041            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9042            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9043                s.select(selections)
 9044            });
 9045        });
 9046    }
 9047
 9048    fn indent_selection(
 9049        buffer: &MultiBuffer,
 9050        snapshot: &MultiBufferSnapshot,
 9051        selection: &mut Selection<Point>,
 9052        edits: &mut Vec<(Range<Point>, String)>,
 9053        delta_for_start_row: u32,
 9054        cx: &App,
 9055    ) -> u32 {
 9056        let settings = buffer.language_settings_at(selection.start, cx);
 9057        let tab_size = settings.tab_size.get();
 9058        let indent_kind = if settings.hard_tabs {
 9059            IndentKind::Tab
 9060        } else {
 9061            IndentKind::Space
 9062        };
 9063        let mut start_row = selection.start.row;
 9064        let mut end_row = selection.end.row + 1;
 9065
 9066        // If a selection ends at the beginning of a line, don't indent
 9067        // that last line.
 9068        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9069            end_row -= 1;
 9070        }
 9071
 9072        // Avoid re-indenting a row that has already been indented by a
 9073        // previous selection, but still update this selection's column
 9074        // to reflect that indentation.
 9075        if delta_for_start_row > 0 {
 9076            start_row += 1;
 9077            selection.start.column += delta_for_start_row;
 9078            if selection.end.row == selection.start.row {
 9079                selection.end.column += delta_for_start_row;
 9080            }
 9081        }
 9082
 9083        let mut delta_for_end_row = 0;
 9084        let has_multiple_rows = start_row + 1 != end_row;
 9085        for row in start_row..end_row {
 9086            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9087            let indent_delta = match (current_indent.kind, indent_kind) {
 9088                (IndentKind::Space, IndentKind::Space) => {
 9089                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9090                    IndentSize::spaces(columns_to_next_tab_stop)
 9091                }
 9092                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9093                (_, IndentKind::Tab) => IndentSize::tab(),
 9094            };
 9095
 9096            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9097                0
 9098            } else {
 9099                selection.start.column
 9100            };
 9101            let row_start = Point::new(row, start);
 9102            edits.push((
 9103                row_start..row_start,
 9104                indent_delta.chars().collect::<String>(),
 9105            ));
 9106
 9107            // Update this selection's endpoints to reflect the indentation.
 9108            if row == selection.start.row {
 9109                selection.start.column += indent_delta.len;
 9110            }
 9111            if row == selection.end.row {
 9112                selection.end.column += indent_delta.len;
 9113                delta_for_end_row = indent_delta.len;
 9114            }
 9115        }
 9116
 9117        if selection.start.row == selection.end.row {
 9118            delta_for_start_row + delta_for_end_row
 9119        } else {
 9120            delta_for_end_row
 9121        }
 9122    }
 9123
 9124    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9125        if self.read_only(cx) {
 9126            return;
 9127        }
 9128        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9129        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9130        let selections = self.selections.all::<Point>(cx);
 9131        let mut deletion_ranges = Vec::new();
 9132        let mut last_outdent = None;
 9133        {
 9134            let buffer = self.buffer.read(cx);
 9135            let snapshot = buffer.snapshot(cx);
 9136            for selection in &selections {
 9137                let settings = buffer.language_settings_at(selection.start, cx);
 9138                let tab_size = settings.tab_size.get();
 9139                let mut rows = selection.spanned_rows(false, &display_map);
 9140
 9141                // Avoid re-outdenting a row that has already been outdented by a
 9142                // previous selection.
 9143                if let Some(last_row) = last_outdent {
 9144                    if last_row == rows.start {
 9145                        rows.start = rows.start.next_row();
 9146                    }
 9147                }
 9148                let has_multiple_rows = rows.len() > 1;
 9149                for row in rows.iter_rows() {
 9150                    let indent_size = snapshot.indent_size_for_line(row);
 9151                    if indent_size.len > 0 {
 9152                        let deletion_len = match indent_size.kind {
 9153                            IndentKind::Space => {
 9154                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9155                                if columns_to_prev_tab_stop == 0 {
 9156                                    tab_size
 9157                                } else {
 9158                                    columns_to_prev_tab_stop
 9159                                }
 9160                            }
 9161                            IndentKind::Tab => 1,
 9162                        };
 9163                        let start = if has_multiple_rows
 9164                            || deletion_len > selection.start.column
 9165                            || indent_size.len < selection.start.column
 9166                        {
 9167                            0
 9168                        } else {
 9169                            selection.start.column - deletion_len
 9170                        };
 9171                        deletion_ranges.push(
 9172                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9173                        );
 9174                        last_outdent = Some(row);
 9175                    }
 9176                }
 9177            }
 9178        }
 9179
 9180        self.transact(window, cx, |this, window, cx| {
 9181            this.buffer.update(cx, |buffer, cx| {
 9182                let empty_str: Arc<str> = Arc::default();
 9183                buffer.edit(
 9184                    deletion_ranges
 9185                        .into_iter()
 9186                        .map(|range| (range, empty_str.clone())),
 9187                    None,
 9188                    cx,
 9189                );
 9190            });
 9191            let selections = this.selections.all::<usize>(cx);
 9192            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9193                s.select(selections)
 9194            });
 9195        });
 9196    }
 9197
 9198    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9199        if self.read_only(cx) {
 9200            return;
 9201        }
 9202        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9203        let selections = self
 9204            .selections
 9205            .all::<usize>(cx)
 9206            .into_iter()
 9207            .map(|s| s.range());
 9208
 9209        self.transact(window, cx, |this, window, cx| {
 9210            this.buffer.update(cx, |buffer, cx| {
 9211                buffer.autoindent_ranges(selections, cx);
 9212            });
 9213            let selections = this.selections.all::<usize>(cx);
 9214            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9215                s.select(selections)
 9216            });
 9217        });
 9218    }
 9219
 9220    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9221        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9222        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9223        let selections = self.selections.all::<Point>(cx);
 9224
 9225        let mut new_cursors = Vec::new();
 9226        let mut edit_ranges = Vec::new();
 9227        let mut selections = selections.iter().peekable();
 9228        while let Some(selection) = selections.next() {
 9229            let mut rows = selection.spanned_rows(false, &display_map);
 9230            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9231
 9232            // Accumulate contiguous regions of rows that we want to delete.
 9233            while let Some(next_selection) = selections.peek() {
 9234                let next_rows = next_selection.spanned_rows(false, &display_map);
 9235                if next_rows.start <= rows.end {
 9236                    rows.end = next_rows.end;
 9237                    selections.next().unwrap();
 9238                } else {
 9239                    break;
 9240                }
 9241            }
 9242
 9243            let buffer = &display_map.buffer_snapshot;
 9244            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9245            let edit_end;
 9246            let cursor_buffer_row;
 9247            if buffer.max_point().row >= rows.end.0 {
 9248                // If there's a line after the range, delete the \n from the end of the row range
 9249                // and position the cursor on the next line.
 9250                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9251                cursor_buffer_row = rows.end;
 9252            } else {
 9253                // If there isn't a line after the range, delete the \n from the line before the
 9254                // start of the row range and position the cursor there.
 9255                edit_start = edit_start.saturating_sub(1);
 9256                edit_end = buffer.len();
 9257                cursor_buffer_row = rows.start.previous_row();
 9258            }
 9259
 9260            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9261            *cursor.column_mut() =
 9262                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9263
 9264            new_cursors.push((
 9265                selection.id,
 9266                buffer.anchor_after(cursor.to_point(&display_map)),
 9267            ));
 9268            edit_ranges.push(edit_start..edit_end);
 9269        }
 9270
 9271        self.transact(window, cx, |this, window, cx| {
 9272            let buffer = this.buffer.update(cx, |buffer, cx| {
 9273                let empty_str: Arc<str> = Arc::default();
 9274                buffer.edit(
 9275                    edit_ranges
 9276                        .into_iter()
 9277                        .map(|range| (range, empty_str.clone())),
 9278                    None,
 9279                    cx,
 9280                );
 9281                buffer.snapshot(cx)
 9282            });
 9283            let new_selections = new_cursors
 9284                .into_iter()
 9285                .map(|(id, cursor)| {
 9286                    let cursor = cursor.to_point(&buffer);
 9287                    Selection {
 9288                        id,
 9289                        start: cursor,
 9290                        end: cursor,
 9291                        reversed: false,
 9292                        goal: SelectionGoal::None,
 9293                    }
 9294                })
 9295                .collect();
 9296
 9297            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9298                s.select(new_selections);
 9299            });
 9300        });
 9301    }
 9302
 9303    pub fn join_lines_impl(
 9304        &mut self,
 9305        insert_whitespace: bool,
 9306        window: &mut Window,
 9307        cx: &mut Context<Self>,
 9308    ) {
 9309        if self.read_only(cx) {
 9310            return;
 9311        }
 9312        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9313        for selection in self.selections.all::<Point>(cx) {
 9314            let start = MultiBufferRow(selection.start.row);
 9315            // Treat single line selections as if they include the next line. Otherwise this action
 9316            // would do nothing for single line selections individual cursors.
 9317            let end = if selection.start.row == selection.end.row {
 9318                MultiBufferRow(selection.start.row + 1)
 9319            } else {
 9320                MultiBufferRow(selection.end.row)
 9321            };
 9322
 9323            if let Some(last_row_range) = row_ranges.last_mut() {
 9324                if start <= last_row_range.end {
 9325                    last_row_range.end = end;
 9326                    continue;
 9327                }
 9328            }
 9329            row_ranges.push(start..end);
 9330        }
 9331
 9332        let snapshot = self.buffer.read(cx).snapshot(cx);
 9333        let mut cursor_positions = Vec::new();
 9334        for row_range in &row_ranges {
 9335            let anchor = snapshot.anchor_before(Point::new(
 9336                row_range.end.previous_row().0,
 9337                snapshot.line_len(row_range.end.previous_row()),
 9338            ));
 9339            cursor_positions.push(anchor..anchor);
 9340        }
 9341
 9342        self.transact(window, cx, |this, window, cx| {
 9343            for row_range in row_ranges.into_iter().rev() {
 9344                for row in row_range.iter_rows().rev() {
 9345                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9346                    let next_line_row = row.next_row();
 9347                    let indent = snapshot.indent_size_for_line(next_line_row);
 9348                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9349
 9350                    let replace =
 9351                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9352                            " "
 9353                        } else {
 9354                            ""
 9355                        };
 9356
 9357                    this.buffer.update(cx, |buffer, cx| {
 9358                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9359                    });
 9360                }
 9361            }
 9362
 9363            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9364                s.select_anchor_ranges(cursor_positions)
 9365            });
 9366        });
 9367    }
 9368
 9369    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9370        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9371        self.join_lines_impl(true, window, cx);
 9372    }
 9373
 9374    pub fn sort_lines_case_sensitive(
 9375        &mut self,
 9376        _: &SortLinesCaseSensitive,
 9377        window: &mut Window,
 9378        cx: &mut Context<Self>,
 9379    ) {
 9380        self.manipulate_lines(window, cx, |lines| lines.sort())
 9381    }
 9382
 9383    pub fn sort_lines_case_insensitive(
 9384        &mut self,
 9385        _: &SortLinesCaseInsensitive,
 9386        window: &mut Window,
 9387        cx: &mut Context<Self>,
 9388    ) {
 9389        self.manipulate_lines(window, cx, |lines| {
 9390            lines.sort_by_key(|line| line.to_lowercase())
 9391        })
 9392    }
 9393
 9394    pub fn unique_lines_case_insensitive(
 9395        &mut self,
 9396        _: &UniqueLinesCaseInsensitive,
 9397        window: &mut Window,
 9398        cx: &mut Context<Self>,
 9399    ) {
 9400        self.manipulate_lines(window, cx, |lines| {
 9401            let mut seen = HashSet::default();
 9402            lines.retain(|line| seen.insert(line.to_lowercase()));
 9403        })
 9404    }
 9405
 9406    pub fn unique_lines_case_sensitive(
 9407        &mut self,
 9408        _: &UniqueLinesCaseSensitive,
 9409        window: &mut Window,
 9410        cx: &mut Context<Self>,
 9411    ) {
 9412        self.manipulate_lines(window, cx, |lines| {
 9413            let mut seen = HashSet::default();
 9414            lines.retain(|line| seen.insert(*line));
 9415        })
 9416    }
 9417
 9418    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9419        let Some(project) = self.project.clone() else {
 9420            return;
 9421        };
 9422        self.reload(project, window, cx)
 9423            .detach_and_notify_err(window, cx);
 9424    }
 9425
 9426    pub fn restore_file(
 9427        &mut self,
 9428        _: &::git::RestoreFile,
 9429        window: &mut Window,
 9430        cx: &mut Context<Self>,
 9431    ) {
 9432        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9433        let mut buffer_ids = HashSet::default();
 9434        let snapshot = self.buffer().read(cx).snapshot(cx);
 9435        for selection in self.selections.all::<usize>(cx) {
 9436            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9437        }
 9438
 9439        let buffer = self.buffer().read(cx);
 9440        let ranges = buffer_ids
 9441            .into_iter()
 9442            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9443            .collect::<Vec<_>>();
 9444
 9445        self.restore_hunks_in_ranges(ranges, window, cx);
 9446    }
 9447
 9448    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9449        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9450        let selections = self
 9451            .selections
 9452            .all(cx)
 9453            .into_iter()
 9454            .map(|s| s.range())
 9455            .collect();
 9456        self.restore_hunks_in_ranges(selections, window, cx);
 9457    }
 9458
 9459    pub fn restore_hunks_in_ranges(
 9460        &mut self,
 9461        ranges: Vec<Range<Point>>,
 9462        window: &mut Window,
 9463        cx: &mut Context<Editor>,
 9464    ) {
 9465        let mut revert_changes = HashMap::default();
 9466        let chunk_by = self
 9467            .snapshot(window, cx)
 9468            .hunks_for_ranges(ranges)
 9469            .into_iter()
 9470            .chunk_by(|hunk| hunk.buffer_id);
 9471        for (buffer_id, hunks) in &chunk_by {
 9472            let hunks = hunks.collect::<Vec<_>>();
 9473            for hunk in &hunks {
 9474                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9475            }
 9476            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9477        }
 9478        drop(chunk_by);
 9479        if !revert_changes.is_empty() {
 9480            self.transact(window, cx, |editor, window, cx| {
 9481                editor.restore(revert_changes, window, cx);
 9482            });
 9483        }
 9484    }
 9485
 9486    pub fn open_active_item_in_terminal(
 9487        &mut self,
 9488        _: &OpenInTerminal,
 9489        window: &mut Window,
 9490        cx: &mut Context<Self>,
 9491    ) {
 9492        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9493            let project_path = buffer.read(cx).project_path(cx)?;
 9494            let project = self.project.as_ref()?.read(cx);
 9495            let entry = project.entry_for_path(&project_path, cx)?;
 9496            let parent = match &entry.canonical_path {
 9497                Some(canonical_path) => canonical_path.to_path_buf(),
 9498                None => project.absolute_path(&project_path, cx)?,
 9499            }
 9500            .parent()?
 9501            .to_path_buf();
 9502            Some(parent)
 9503        }) {
 9504            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 9505        }
 9506    }
 9507
 9508    fn set_breakpoint_context_menu(
 9509        &mut self,
 9510        display_row: DisplayRow,
 9511        position: Option<Anchor>,
 9512        clicked_point: gpui::Point<Pixels>,
 9513        window: &mut Window,
 9514        cx: &mut Context<Self>,
 9515    ) {
 9516        if !cx.has_flag::<DebuggerFeatureFlag>() {
 9517            return;
 9518        }
 9519        let source = self
 9520            .buffer
 9521            .read(cx)
 9522            .snapshot(cx)
 9523            .anchor_before(Point::new(display_row.0, 0u32));
 9524
 9525        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 9526
 9527        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
 9528            self,
 9529            source,
 9530            clicked_point,
 9531            context_menu,
 9532            window,
 9533            cx,
 9534        );
 9535    }
 9536
 9537    fn add_edit_breakpoint_block(
 9538        &mut self,
 9539        anchor: Anchor,
 9540        breakpoint: &Breakpoint,
 9541        edit_action: BreakpointPromptEditAction,
 9542        window: &mut Window,
 9543        cx: &mut Context<Self>,
 9544    ) {
 9545        let weak_editor = cx.weak_entity();
 9546        let bp_prompt = cx.new(|cx| {
 9547            BreakpointPromptEditor::new(
 9548                weak_editor,
 9549                anchor,
 9550                breakpoint.clone(),
 9551                edit_action,
 9552                window,
 9553                cx,
 9554            )
 9555        });
 9556
 9557        let height = bp_prompt.update(cx, |this, cx| {
 9558            this.prompt
 9559                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
 9560        });
 9561        let cloned_prompt = bp_prompt.clone();
 9562        let blocks = vec![BlockProperties {
 9563            style: BlockStyle::Sticky,
 9564            placement: BlockPlacement::Above(anchor),
 9565            height: Some(height),
 9566            render: Arc::new(move |cx| {
 9567                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
 9568                cloned_prompt.clone().into_any_element()
 9569            }),
 9570            priority: 0,
 9571            render_in_minimap: true,
 9572        }];
 9573
 9574        let focus_handle = bp_prompt.focus_handle(cx);
 9575        window.focus(&focus_handle);
 9576
 9577        let block_ids = self.insert_blocks(blocks, None, cx);
 9578        bp_prompt.update(cx, |prompt, _| {
 9579            prompt.add_block_ids(block_ids);
 9580        });
 9581    }
 9582
 9583    pub(crate) fn breakpoint_at_row(
 9584        &self,
 9585        row: u32,
 9586        window: &mut Window,
 9587        cx: &mut Context<Self>,
 9588    ) -> Option<(Anchor, Breakpoint)> {
 9589        let snapshot = self.snapshot(window, cx);
 9590        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
 9591
 9592        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9593    }
 9594
 9595    pub(crate) fn breakpoint_at_anchor(
 9596        &self,
 9597        breakpoint_position: Anchor,
 9598        snapshot: &EditorSnapshot,
 9599        cx: &mut Context<Self>,
 9600    ) -> Option<(Anchor, Breakpoint)> {
 9601        let project = self.project.clone()?;
 9602
 9603        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
 9604            snapshot
 9605                .buffer_snapshot
 9606                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
 9607        })?;
 9608
 9609        let enclosing_excerpt = breakpoint_position.excerpt_id;
 9610        let buffer = project.read_with(cx, |project, cx| project.buffer_for_id(buffer_id, cx))?;
 9611        let buffer_snapshot = buffer.read(cx).snapshot();
 9612
 9613        let row = buffer_snapshot
 9614            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
 9615            .row;
 9616
 9617        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
 9618        let anchor_end = snapshot
 9619            .buffer_snapshot
 9620            .anchor_after(Point::new(row, line_len));
 9621
 9622        let bp = self
 9623            .breakpoint_store
 9624            .as_ref()?
 9625            .read_with(cx, |breakpoint_store, cx| {
 9626                breakpoint_store
 9627                    .breakpoints(
 9628                        &buffer,
 9629                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
 9630                        &buffer_snapshot,
 9631                        cx,
 9632                    )
 9633                    .next()
 9634                    .and_then(|(anchor, bp)| {
 9635                        let breakpoint_row = buffer_snapshot
 9636                            .summary_for_anchor::<text::PointUtf16>(anchor)
 9637                            .row;
 9638
 9639                        if breakpoint_row == row {
 9640                            snapshot
 9641                                .buffer_snapshot
 9642                                .anchor_in_excerpt(enclosing_excerpt, *anchor)
 9643                                .map(|anchor| (anchor, bp.clone()))
 9644                        } else {
 9645                            None
 9646                        }
 9647                    })
 9648            });
 9649        bp
 9650    }
 9651
 9652    pub fn edit_log_breakpoint(
 9653        &mut self,
 9654        _: &EditLogBreakpoint,
 9655        window: &mut Window,
 9656        cx: &mut Context<Self>,
 9657    ) {
 9658        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9659            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
 9660                message: None,
 9661                state: BreakpointState::Enabled,
 9662                condition: None,
 9663                hit_condition: None,
 9664            });
 9665
 9666            self.add_edit_breakpoint_block(
 9667                anchor,
 9668                &breakpoint,
 9669                BreakpointPromptEditAction::Log,
 9670                window,
 9671                cx,
 9672            );
 9673        }
 9674    }
 9675
 9676    fn breakpoints_at_cursors(
 9677        &self,
 9678        window: &mut Window,
 9679        cx: &mut Context<Self>,
 9680    ) -> Vec<(Anchor, Option<Breakpoint>)> {
 9681        let snapshot = self.snapshot(window, cx);
 9682        let cursors = self
 9683            .selections
 9684            .disjoint_anchors()
 9685            .into_iter()
 9686            .map(|selection| {
 9687                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
 9688
 9689                let breakpoint_position = self
 9690                    .breakpoint_at_row(cursor_position.row, window, cx)
 9691                    .map(|bp| bp.0)
 9692                    .unwrap_or_else(|| {
 9693                        snapshot
 9694                            .display_snapshot
 9695                            .buffer_snapshot
 9696                            .anchor_after(Point::new(cursor_position.row, 0))
 9697                    });
 9698
 9699                let breakpoint = self
 9700                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9701                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
 9702
 9703                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
 9704            })
 9705            // 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.
 9706            .collect::<HashMap<Anchor, _>>();
 9707
 9708        cursors.into_iter().collect()
 9709    }
 9710
 9711    pub fn enable_breakpoint(
 9712        &mut self,
 9713        _: &crate::actions::EnableBreakpoint,
 9714        window: &mut Window,
 9715        cx: &mut Context<Self>,
 9716    ) {
 9717        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9718            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
 9719                continue;
 9720            };
 9721            self.edit_breakpoint_at_anchor(
 9722                anchor,
 9723                breakpoint,
 9724                BreakpointEditAction::InvertState,
 9725                cx,
 9726            );
 9727        }
 9728    }
 9729
 9730    pub fn disable_breakpoint(
 9731        &mut self,
 9732        _: &crate::actions::DisableBreakpoint,
 9733        window: &mut Window,
 9734        cx: &mut Context<Self>,
 9735    ) {
 9736        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9737            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
 9738                continue;
 9739            };
 9740            self.edit_breakpoint_at_anchor(
 9741                anchor,
 9742                breakpoint,
 9743                BreakpointEditAction::InvertState,
 9744                cx,
 9745            );
 9746        }
 9747    }
 9748
 9749    pub fn toggle_breakpoint(
 9750        &mut self,
 9751        _: &crate::actions::ToggleBreakpoint,
 9752        window: &mut Window,
 9753        cx: &mut Context<Self>,
 9754    ) {
 9755        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9756            if let Some(breakpoint) = breakpoint {
 9757                self.edit_breakpoint_at_anchor(
 9758                    anchor,
 9759                    breakpoint,
 9760                    BreakpointEditAction::Toggle,
 9761                    cx,
 9762                );
 9763            } else {
 9764                self.edit_breakpoint_at_anchor(
 9765                    anchor,
 9766                    Breakpoint::new_standard(),
 9767                    BreakpointEditAction::Toggle,
 9768                    cx,
 9769                );
 9770            }
 9771        }
 9772    }
 9773
 9774    pub fn edit_breakpoint_at_anchor(
 9775        &mut self,
 9776        breakpoint_position: Anchor,
 9777        breakpoint: Breakpoint,
 9778        edit_action: BreakpointEditAction,
 9779        cx: &mut Context<Self>,
 9780    ) {
 9781        let Some(breakpoint_store) = &self.breakpoint_store else {
 9782            return;
 9783        };
 9784
 9785        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
 9786            if breakpoint_position == Anchor::min() {
 9787                self.buffer()
 9788                    .read(cx)
 9789                    .excerpt_buffer_ids()
 9790                    .into_iter()
 9791                    .next()
 9792            } else {
 9793                None
 9794            }
 9795        }) else {
 9796            return;
 9797        };
 9798
 9799        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
 9800            return;
 9801        };
 9802
 9803        breakpoint_store.update(cx, |breakpoint_store, cx| {
 9804            breakpoint_store.toggle_breakpoint(
 9805                buffer,
 9806                (breakpoint_position.text_anchor, breakpoint),
 9807                edit_action,
 9808                cx,
 9809            );
 9810        });
 9811
 9812        cx.notify();
 9813    }
 9814
 9815    #[cfg(any(test, feature = "test-support"))]
 9816    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
 9817        self.breakpoint_store.clone()
 9818    }
 9819
 9820    pub fn prepare_restore_change(
 9821        &self,
 9822        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
 9823        hunk: &MultiBufferDiffHunk,
 9824        cx: &mut App,
 9825    ) -> Option<()> {
 9826        if hunk.is_created_file() {
 9827            return None;
 9828        }
 9829        let buffer = self.buffer.read(cx);
 9830        let diff = buffer.diff_for(hunk.buffer_id)?;
 9831        let buffer = buffer.buffer(hunk.buffer_id)?;
 9832        let buffer = buffer.read(cx);
 9833        let original_text = diff
 9834            .read(cx)
 9835            .base_text()
 9836            .as_rope()
 9837            .slice(hunk.diff_base_byte_range.clone());
 9838        let buffer_snapshot = buffer.snapshot();
 9839        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
 9840        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
 9841            probe
 9842                .0
 9843                .start
 9844                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
 9845                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
 9846        }) {
 9847            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
 9848            Some(())
 9849        } else {
 9850            None
 9851        }
 9852    }
 9853
 9854    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
 9855        self.manipulate_lines(window, cx, |lines| lines.reverse())
 9856    }
 9857
 9858    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
 9859        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
 9860    }
 9861
 9862    fn manipulate_lines<Fn>(
 9863        &mut self,
 9864        window: &mut Window,
 9865        cx: &mut Context<Self>,
 9866        mut callback: Fn,
 9867    ) where
 9868        Fn: FnMut(&mut Vec<&str>),
 9869    {
 9870        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9871
 9872        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9873        let buffer = self.buffer.read(cx).snapshot(cx);
 9874
 9875        let mut edits = Vec::new();
 9876
 9877        let selections = self.selections.all::<Point>(cx);
 9878        let mut selections = selections.iter().peekable();
 9879        let mut contiguous_row_selections = Vec::new();
 9880        let mut new_selections = Vec::new();
 9881        let mut added_lines = 0;
 9882        let mut removed_lines = 0;
 9883
 9884        while let Some(selection) = selections.next() {
 9885            let (start_row, end_row) = consume_contiguous_rows(
 9886                &mut contiguous_row_selections,
 9887                selection,
 9888                &display_map,
 9889                &mut selections,
 9890            );
 9891
 9892            let start_point = Point::new(start_row.0, 0);
 9893            let end_point = Point::new(
 9894                end_row.previous_row().0,
 9895                buffer.line_len(end_row.previous_row()),
 9896            );
 9897            let text = buffer
 9898                .text_for_range(start_point..end_point)
 9899                .collect::<String>();
 9900
 9901            let mut lines = text.split('\n').collect_vec();
 9902
 9903            let lines_before = lines.len();
 9904            callback(&mut lines);
 9905            let lines_after = lines.len();
 9906
 9907            edits.push((start_point..end_point, lines.join("\n")));
 9908
 9909            // Selections must change based on added and removed line count
 9910            let start_row =
 9911                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
 9912            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
 9913            new_selections.push(Selection {
 9914                id: selection.id,
 9915                start: start_row,
 9916                end: end_row,
 9917                goal: SelectionGoal::None,
 9918                reversed: selection.reversed,
 9919            });
 9920
 9921            if lines_after > lines_before {
 9922                added_lines += lines_after - lines_before;
 9923            } else if lines_before > lines_after {
 9924                removed_lines += lines_before - lines_after;
 9925            }
 9926        }
 9927
 9928        self.transact(window, cx, |this, window, cx| {
 9929            let buffer = this.buffer.update(cx, |buffer, cx| {
 9930                buffer.edit(edits, None, cx);
 9931                buffer.snapshot(cx)
 9932            });
 9933
 9934            // Recalculate offsets on newly edited buffer
 9935            let new_selections = new_selections
 9936                .iter()
 9937                .map(|s| {
 9938                    let start_point = Point::new(s.start.0, 0);
 9939                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
 9940                    Selection {
 9941                        id: s.id,
 9942                        start: buffer.point_to_offset(start_point),
 9943                        end: buffer.point_to_offset(end_point),
 9944                        goal: s.goal,
 9945                        reversed: s.reversed,
 9946                    }
 9947                })
 9948                .collect();
 9949
 9950            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9951                s.select(new_selections);
 9952            });
 9953
 9954            this.request_autoscroll(Autoscroll::fit(), cx);
 9955        });
 9956    }
 9957
 9958    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
 9959        self.manipulate_text(window, cx, |text| {
 9960            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
 9961            if has_upper_case_characters {
 9962                text.to_lowercase()
 9963            } else {
 9964                text.to_uppercase()
 9965            }
 9966        })
 9967    }
 9968
 9969    pub fn convert_to_upper_case(
 9970        &mut self,
 9971        _: &ConvertToUpperCase,
 9972        window: &mut Window,
 9973        cx: &mut Context<Self>,
 9974    ) {
 9975        self.manipulate_text(window, cx, |text| text.to_uppercase())
 9976    }
 9977
 9978    pub fn convert_to_lower_case(
 9979        &mut self,
 9980        _: &ConvertToLowerCase,
 9981        window: &mut Window,
 9982        cx: &mut Context<Self>,
 9983    ) {
 9984        self.manipulate_text(window, cx, |text| text.to_lowercase())
 9985    }
 9986
 9987    pub fn convert_to_title_case(
 9988        &mut self,
 9989        _: &ConvertToTitleCase,
 9990        window: &mut Window,
 9991        cx: &mut Context<Self>,
 9992    ) {
 9993        self.manipulate_text(window, cx, |text| {
 9994            text.split('\n')
 9995                .map(|line| line.to_case(Case::Title))
 9996                .join("\n")
 9997        })
 9998    }
 9999
10000    pub fn convert_to_snake_case(
10001        &mut self,
10002        _: &ConvertToSnakeCase,
10003        window: &mut Window,
10004        cx: &mut Context<Self>,
10005    ) {
10006        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10007    }
10008
10009    pub fn convert_to_kebab_case(
10010        &mut self,
10011        _: &ConvertToKebabCase,
10012        window: &mut Window,
10013        cx: &mut Context<Self>,
10014    ) {
10015        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10016    }
10017
10018    pub fn convert_to_upper_camel_case(
10019        &mut self,
10020        _: &ConvertToUpperCamelCase,
10021        window: &mut Window,
10022        cx: &mut Context<Self>,
10023    ) {
10024        self.manipulate_text(window, cx, |text| {
10025            text.split('\n')
10026                .map(|line| line.to_case(Case::UpperCamel))
10027                .join("\n")
10028        })
10029    }
10030
10031    pub fn convert_to_lower_camel_case(
10032        &mut self,
10033        _: &ConvertToLowerCamelCase,
10034        window: &mut Window,
10035        cx: &mut Context<Self>,
10036    ) {
10037        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10038    }
10039
10040    pub fn convert_to_opposite_case(
10041        &mut self,
10042        _: &ConvertToOppositeCase,
10043        window: &mut Window,
10044        cx: &mut Context<Self>,
10045    ) {
10046        self.manipulate_text(window, cx, |text| {
10047            text.chars()
10048                .fold(String::with_capacity(text.len()), |mut t, c| {
10049                    if c.is_uppercase() {
10050                        t.extend(c.to_lowercase());
10051                    } else {
10052                        t.extend(c.to_uppercase());
10053                    }
10054                    t
10055                })
10056        })
10057    }
10058
10059    pub fn convert_to_rot13(
10060        &mut self,
10061        _: &ConvertToRot13,
10062        window: &mut Window,
10063        cx: &mut Context<Self>,
10064    ) {
10065        self.manipulate_text(window, cx, |text| {
10066            text.chars()
10067                .map(|c| match c {
10068                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10069                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10070                    _ => c,
10071                })
10072                .collect()
10073        })
10074    }
10075
10076    pub fn convert_to_rot47(
10077        &mut self,
10078        _: &ConvertToRot47,
10079        window: &mut Window,
10080        cx: &mut Context<Self>,
10081    ) {
10082        self.manipulate_text(window, cx, |text| {
10083            text.chars()
10084                .map(|c| {
10085                    let code_point = c as u32;
10086                    if code_point >= 33 && code_point <= 126 {
10087                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10088                    }
10089                    c
10090                })
10091                .collect()
10092        })
10093    }
10094
10095    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10096    where
10097        Fn: FnMut(&str) -> String,
10098    {
10099        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10100        let buffer = self.buffer.read(cx).snapshot(cx);
10101
10102        let mut new_selections = Vec::new();
10103        let mut edits = Vec::new();
10104        let mut selection_adjustment = 0i32;
10105
10106        for selection in self.selections.all::<usize>(cx) {
10107            let selection_is_empty = selection.is_empty();
10108
10109            let (start, end) = if selection_is_empty {
10110                let word_range = movement::surrounding_word(
10111                    &display_map,
10112                    selection.start.to_display_point(&display_map),
10113                );
10114                let start = word_range.start.to_offset(&display_map, Bias::Left);
10115                let end = word_range.end.to_offset(&display_map, Bias::Left);
10116                (start, end)
10117            } else {
10118                (selection.start, selection.end)
10119            };
10120
10121            let text = buffer.text_for_range(start..end).collect::<String>();
10122            let old_length = text.len() as i32;
10123            let text = callback(&text);
10124
10125            new_selections.push(Selection {
10126                start: (start as i32 - selection_adjustment) as usize,
10127                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10128                goal: SelectionGoal::None,
10129                ..selection
10130            });
10131
10132            selection_adjustment += old_length - text.len() as i32;
10133
10134            edits.push((start..end, text));
10135        }
10136
10137        self.transact(window, cx, |this, window, cx| {
10138            this.buffer.update(cx, |buffer, cx| {
10139                buffer.edit(edits, None, cx);
10140            });
10141
10142            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10143                s.select(new_selections);
10144            });
10145
10146            this.request_autoscroll(Autoscroll::fit(), cx);
10147        });
10148    }
10149
10150    pub fn duplicate(
10151        &mut self,
10152        upwards: bool,
10153        whole_lines: bool,
10154        window: &mut Window,
10155        cx: &mut Context<Self>,
10156    ) {
10157        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10158
10159        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10160        let buffer = &display_map.buffer_snapshot;
10161        let selections = self.selections.all::<Point>(cx);
10162
10163        let mut edits = Vec::new();
10164        let mut selections_iter = selections.iter().peekable();
10165        while let Some(selection) = selections_iter.next() {
10166            let mut rows = selection.spanned_rows(false, &display_map);
10167            // duplicate line-wise
10168            if whole_lines || selection.start == selection.end {
10169                // Avoid duplicating the same lines twice.
10170                while let Some(next_selection) = selections_iter.peek() {
10171                    let next_rows = next_selection.spanned_rows(false, &display_map);
10172                    if next_rows.start < rows.end {
10173                        rows.end = next_rows.end;
10174                        selections_iter.next().unwrap();
10175                    } else {
10176                        break;
10177                    }
10178                }
10179
10180                // Copy the text from the selected row region and splice it either at the start
10181                // or end of the region.
10182                let start = Point::new(rows.start.0, 0);
10183                let end = Point::new(
10184                    rows.end.previous_row().0,
10185                    buffer.line_len(rows.end.previous_row()),
10186                );
10187                let text = buffer
10188                    .text_for_range(start..end)
10189                    .chain(Some("\n"))
10190                    .collect::<String>();
10191                let insert_location = if upwards {
10192                    Point::new(rows.end.0, 0)
10193                } else {
10194                    start
10195                };
10196                edits.push((insert_location..insert_location, text));
10197            } else {
10198                // duplicate character-wise
10199                let start = selection.start;
10200                let end = selection.end;
10201                let text = buffer.text_for_range(start..end).collect::<String>();
10202                edits.push((selection.end..selection.end, text));
10203            }
10204        }
10205
10206        self.transact(window, cx, |this, _, cx| {
10207            this.buffer.update(cx, |buffer, cx| {
10208                buffer.edit(edits, None, cx);
10209            });
10210
10211            this.request_autoscroll(Autoscroll::fit(), cx);
10212        });
10213    }
10214
10215    pub fn duplicate_line_up(
10216        &mut self,
10217        _: &DuplicateLineUp,
10218        window: &mut Window,
10219        cx: &mut Context<Self>,
10220    ) {
10221        self.duplicate(true, true, window, cx);
10222    }
10223
10224    pub fn duplicate_line_down(
10225        &mut self,
10226        _: &DuplicateLineDown,
10227        window: &mut Window,
10228        cx: &mut Context<Self>,
10229    ) {
10230        self.duplicate(false, true, window, cx);
10231    }
10232
10233    pub fn duplicate_selection(
10234        &mut self,
10235        _: &DuplicateSelection,
10236        window: &mut Window,
10237        cx: &mut Context<Self>,
10238    ) {
10239        self.duplicate(false, false, window, cx);
10240    }
10241
10242    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10243        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10244
10245        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10246        let buffer = self.buffer.read(cx).snapshot(cx);
10247
10248        let mut edits = Vec::new();
10249        let mut unfold_ranges = Vec::new();
10250        let mut refold_creases = Vec::new();
10251
10252        let selections = self.selections.all::<Point>(cx);
10253        let mut selections = selections.iter().peekable();
10254        let mut contiguous_row_selections = Vec::new();
10255        let mut new_selections = Vec::new();
10256
10257        while let Some(selection) = selections.next() {
10258            // Find all the selections that span a contiguous row range
10259            let (start_row, end_row) = consume_contiguous_rows(
10260                &mut contiguous_row_selections,
10261                selection,
10262                &display_map,
10263                &mut selections,
10264            );
10265
10266            // Move the text spanned by the row range to be before the line preceding the row range
10267            if start_row.0 > 0 {
10268                let range_to_move = Point::new(
10269                    start_row.previous_row().0,
10270                    buffer.line_len(start_row.previous_row()),
10271                )
10272                    ..Point::new(
10273                        end_row.previous_row().0,
10274                        buffer.line_len(end_row.previous_row()),
10275                    );
10276                let insertion_point = display_map
10277                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10278                    .0;
10279
10280                // Don't move lines across excerpts
10281                if buffer
10282                    .excerpt_containing(insertion_point..range_to_move.end)
10283                    .is_some()
10284                {
10285                    let text = buffer
10286                        .text_for_range(range_to_move.clone())
10287                        .flat_map(|s| s.chars())
10288                        .skip(1)
10289                        .chain(['\n'])
10290                        .collect::<String>();
10291
10292                    edits.push((
10293                        buffer.anchor_after(range_to_move.start)
10294                            ..buffer.anchor_before(range_to_move.end),
10295                        String::new(),
10296                    ));
10297                    let insertion_anchor = buffer.anchor_after(insertion_point);
10298                    edits.push((insertion_anchor..insertion_anchor, text));
10299
10300                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10301
10302                    // Move selections up
10303                    new_selections.extend(contiguous_row_selections.drain(..).map(
10304                        |mut selection| {
10305                            selection.start.row -= row_delta;
10306                            selection.end.row -= row_delta;
10307                            selection
10308                        },
10309                    ));
10310
10311                    // Move folds up
10312                    unfold_ranges.push(range_to_move.clone());
10313                    for fold in display_map.folds_in_range(
10314                        buffer.anchor_before(range_to_move.start)
10315                            ..buffer.anchor_after(range_to_move.end),
10316                    ) {
10317                        let mut start = fold.range.start.to_point(&buffer);
10318                        let mut end = fold.range.end.to_point(&buffer);
10319                        start.row -= row_delta;
10320                        end.row -= row_delta;
10321                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10322                    }
10323                }
10324            }
10325
10326            // If we didn't move line(s), preserve the existing selections
10327            new_selections.append(&mut contiguous_row_selections);
10328        }
10329
10330        self.transact(window, cx, |this, window, cx| {
10331            this.unfold_ranges(&unfold_ranges, true, true, cx);
10332            this.buffer.update(cx, |buffer, cx| {
10333                for (range, text) in edits {
10334                    buffer.edit([(range, text)], None, cx);
10335                }
10336            });
10337            this.fold_creases(refold_creases, true, window, cx);
10338            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10339                s.select(new_selections);
10340            })
10341        });
10342    }
10343
10344    pub fn move_line_down(
10345        &mut self,
10346        _: &MoveLineDown,
10347        window: &mut Window,
10348        cx: &mut Context<Self>,
10349    ) {
10350        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10351
10352        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10353        let buffer = self.buffer.read(cx).snapshot(cx);
10354
10355        let mut edits = Vec::new();
10356        let mut unfold_ranges = Vec::new();
10357        let mut refold_creases = Vec::new();
10358
10359        let selections = self.selections.all::<Point>(cx);
10360        let mut selections = selections.iter().peekable();
10361        let mut contiguous_row_selections = Vec::new();
10362        let mut new_selections = Vec::new();
10363
10364        while let Some(selection) = selections.next() {
10365            // Find all the selections that span a contiguous row range
10366            let (start_row, end_row) = consume_contiguous_rows(
10367                &mut contiguous_row_selections,
10368                selection,
10369                &display_map,
10370                &mut selections,
10371            );
10372
10373            // Move the text spanned by the row range to be after the last line of the row range
10374            if end_row.0 <= buffer.max_point().row {
10375                let range_to_move =
10376                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10377                let insertion_point = display_map
10378                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10379                    .0;
10380
10381                // Don't move lines across excerpt boundaries
10382                if buffer
10383                    .excerpt_containing(range_to_move.start..insertion_point)
10384                    .is_some()
10385                {
10386                    let mut text = String::from("\n");
10387                    text.extend(buffer.text_for_range(range_to_move.clone()));
10388                    text.pop(); // Drop trailing newline
10389                    edits.push((
10390                        buffer.anchor_after(range_to_move.start)
10391                            ..buffer.anchor_before(range_to_move.end),
10392                        String::new(),
10393                    ));
10394                    let insertion_anchor = buffer.anchor_after(insertion_point);
10395                    edits.push((insertion_anchor..insertion_anchor, text));
10396
10397                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10398
10399                    // Move selections down
10400                    new_selections.extend(contiguous_row_selections.drain(..).map(
10401                        |mut selection| {
10402                            selection.start.row += row_delta;
10403                            selection.end.row += row_delta;
10404                            selection
10405                        },
10406                    ));
10407
10408                    // Move folds down
10409                    unfold_ranges.push(range_to_move.clone());
10410                    for fold in display_map.folds_in_range(
10411                        buffer.anchor_before(range_to_move.start)
10412                            ..buffer.anchor_after(range_to_move.end),
10413                    ) {
10414                        let mut start = fold.range.start.to_point(&buffer);
10415                        let mut end = fold.range.end.to_point(&buffer);
10416                        start.row += row_delta;
10417                        end.row += row_delta;
10418                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10419                    }
10420                }
10421            }
10422
10423            // If we didn't move line(s), preserve the existing selections
10424            new_selections.append(&mut contiguous_row_selections);
10425        }
10426
10427        self.transact(window, cx, |this, window, cx| {
10428            this.unfold_ranges(&unfold_ranges, true, true, cx);
10429            this.buffer.update(cx, |buffer, cx| {
10430                for (range, text) in edits {
10431                    buffer.edit([(range, text)], None, cx);
10432                }
10433            });
10434            this.fold_creases(refold_creases, true, window, cx);
10435            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10436                s.select(new_selections)
10437            });
10438        });
10439    }
10440
10441    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10442        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10443        let text_layout_details = &self.text_layout_details(window);
10444        self.transact(window, cx, |this, window, cx| {
10445            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10446                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10447                s.move_with(|display_map, selection| {
10448                    if !selection.is_empty() {
10449                        return;
10450                    }
10451
10452                    let mut head = selection.head();
10453                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10454                    if head.column() == display_map.line_len(head.row()) {
10455                        transpose_offset = display_map
10456                            .buffer_snapshot
10457                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10458                    }
10459
10460                    if transpose_offset == 0 {
10461                        return;
10462                    }
10463
10464                    *head.column_mut() += 1;
10465                    head = display_map.clip_point(head, Bias::Right);
10466                    let goal = SelectionGoal::HorizontalPosition(
10467                        display_map
10468                            .x_for_display_point(head, text_layout_details)
10469                            .into(),
10470                    );
10471                    selection.collapse_to(head, goal);
10472
10473                    let transpose_start = display_map
10474                        .buffer_snapshot
10475                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10476                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
10477                        let transpose_end = display_map
10478                            .buffer_snapshot
10479                            .clip_offset(transpose_offset + 1, Bias::Right);
10480                        if let Some(ch) =
10481                            display_map.buffer_snapshot.chars_at(transpose_start).next()
10482                        {
10483                            edits.push((transpose_start..transpose_offset, String::new()));
10484                            edits.push((transpose_end..transpose_end, ch.to_string()));
10485                        }
10486                    }
10487                });
10488                edits
10489            });
10490            this.buffer
10491                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10492            let selections = this.selections.all::<usize>(cx);
10493            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10494                s.select(selections);
10495            });
10496        });
10497    }
10498
10499    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
10500        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10501        self.rewrap_impl(RewrapOptions::default(), cx)
10502    }
10503
10504    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
10505        let buffer = self.buffer.read(cx).snapshot(cx);
10506        let selections = self.selections.all::<Point>(cx);
10507        let mut selections = selections.iter().peekable();
10508
10509        let mut edits = Vec::new();
10510        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
10511
10512        while let Some(selection) = selections.next() {
10513            let mut start_row = selection.start.row;
10514            let mut end_row = selection.end.row;
10515
10516            // Skip selections that overlap with a range that has already been rewrapped.
10517            let selection_range = start_row..end_row;
10518            if rewrapped_row_ranges
10519                .iter()
10520                .any(|range| range.overlaps(&selection_range))
10521            {
10522                continue;
10523            }
10524
10525            let tab_size = buffer.language_settings_at(selection.head(), cx).tab_size;
10526
10527            // Since not all lines in the selection may be at the same indent
10528            // level, choose the indent size that is the most common between all
10529            // of the lines.
10530            //
10531            // If there is a tie, we use the deepest indent.
10532            let (indent_size, indent_end) = {
10533                let mut indent_size_occurrences = HashMap::default();
10534                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
10535
10536                for row in start_row..=end_row {
10537                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
10538                    rows_by_indent_size.entry(indent).or_default().push(row);
10539                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
10540                }
10541
10542                let indent_size = indent_size_occurrences
10543                    .into_iter()
10544                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
10545                    .map(|(indent, _)| indent)
10546                    .unwrap_or_default();
10547                let row = rows_by_indent_size[&indent_size][0];
10548                let indent_end = Point::new(row, indent_size.len);
10549
10550                (indent_size, indent_end)
10551            };
10552
10553            let mut line_prefix = indent_size.chars().collect::<String>();
10554
10555            let mut inside_comment = false;
10556            if let Some(comment_prefix) =
10557                buffer
10558                    .language_scope_at(selection.head())
10559                    .and_then(|language| {
10560                        language
10561                            .line_comment_prefixes()
10562                            .iter()
10563                            .find(|prefix| buffer.contains_str_at(indent_end, prefix))
10564                            .cloned()
10565                    })
10566            {
10567                line_prefix.push_str(&comment_prefix);
10568                inside_comment = true;
10569            }
10570
10571            let language_settings = buffer.language_settings_at(selection.head(), cx);
10572            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
10573                RewrapBehavior::InComments => inside_comment,
10574                RewrapBehavior::InSelections => !selection.is_empty(),
10575                RewrapBehavior::Anywhere => true,
10576            };
10577
10578            let should_rewrap = options.override_language_settings
10579                || allow_rewrap_based_on_language
10580                || self.hard_wrap.is_some();
10581            if !should_rewrap {
10582                continue;
10583            }
10584
10585            if selection.is_empty() {
10586                'expand_upwards: while start_row > 0 {
10587                    let prev_row = start_row - 1;
10588                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
10589                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
10590                    {
10591                        start_row = prev_row;
10592                    } else {
10593                        break 'expand_upwards;
10594                    }
10595                }
10596
10597                'expand_downwards: while end_row < buffer.max_point().row {
10598                    let next_row = end_row + 1;
10599                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
10600                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
10601                    {
10602                        end_row = next_row;
10603                    } else {
10604                        break 'expand_downwards;
10605                    }
10606                }
10607            }
10608
10609            let start = Point::new(start_row, 0);
10610            let start_offset = start.to_offset(&buffer);
10611            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
10612            let selection_text = buffer.text_for_range(start..end).collect::<String>();
10613            let Some(lines_without_prefixes) = selection_text
10614                .lines()
10615                .map(|line| {
10616                    line.strip_prefix(&line_prefix)
10617                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
10618                        .ok_or_else(|| {
10619                            anyhow!("line did not start with prefix {line_prefix:?}: {line:?}")
10620                        })
10621                })
10622                .collect::<Result<Vec<_>, _>>()
10623                .log_err()
10624            else {
10625                continue;
10626            };
10627
10628            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
10629                buffer
10630                    .language_settings_at(Point::new(start_row, 0), cx)
10631                    .preferred_line_length as usize
10632            });
10633            let wrapped_text = wrap_with_prefix(
10634                line_prefix,
10635                lines_without_prefixes.join("\n"),
10636                wrap_column,
10637                tab_size,
10638                options.preserve_existing_whitespace,
10639            );
10640
10641            // TODO: should always use char-based diff while still supporting cursor behavior that
10642            // matches vim.
10643            let mut diff_options = DiffOptions::default();
10644            if options.override_language_settings {
10645                diff_options.max_word_diff_len = 0;
10646                diff_options.max_word_diff_line_count = 0;
10647            } else {
10648                diff_options.max_word_diff_len = usize::MAX;
10649                diff_options.max_word_diff_line_count = usize::MAX;
10650            }
10651
10652            for (old_range, new_text) in
10653                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
10654            {
10655                let edit_start = buffer.anchor_after(start_offset + old_range.start);
10656                let edit_end = buffer.anchor_after(start_offset + old_range.end);
10657                edits.push((edit_start..edit_end, new_text));
10658            }
10659
10660            rewrapped_row_ranges.push(start_row..=end_row);
10661        }
10662
10663        self.buffer
10664            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10665    }
10666
10667    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
10668        let mut text = String::new();
10669        let buffer = self.buffer.read(cx).snapshot(cx);
10670        let mut selections = self.selections.all::<Point>(cx);
10671        let mut clipboard_selections = Vec::with_capacity(selections.len());
10672        {
10673            let max_point = buffer.max_point();
10674            let mut is_first = true;
10675            for selection in &mut selections {
10676                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10677                if is_entire_line {
10678                    selection.start = Point::new(selection.start.row, 0);
10679                    if !selection.is_empty() && selection.end.column == 0 {
10680                        selection.end = cmp::min(max_point, selection.end);
10681                    } else {
10682                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
10683                    }
10684                    selection.goal = SelectionGoal::None;
10685                }
10686                if is_first {
10687                    is_first = false;
10688                } else {
10689                    text += "\n";
10690                }
10691                let mut len = 0;
10692                for chunk in buffer.text_for_range(selection.start..selection.end) {
10693                    text.push_str(chunk);
10694                    len += chunk.len();
10695                }
10696                clipboard_selections.push(ClipboardSelection {
10697                    len,
10698                    is_entire_line,
10699                    first_line_indent: buffer
10700                        .indent_size_for_line(MultiBufferRow(selection.start.row))
10701                        .len,
10702                });
10703            }
10704        }
10705
10706        self.transact(window, cx, |this, window, cx| {
10707            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10708                s.select(selections);
10709            });
10710            this.insert("", window, cx);
10711        });
10712        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
10713    }
10714
10715    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
10716        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10717        let item = self.cut_common(window, cx);
10718        cx.write_to_clipboard(item);
10719    }
10720
10721    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
10722        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10723        self.change_selections(None, window, cx, |s| {
10724            s.move_with(|snapshot, sel| {
10725                if sel.is_empty() {
10726                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
10727                }
10728            });
10729        });
10730        let item = self.cut_common(window, cx);
10731        cx.set_global(KillRing(item))
10732    }
10733
10734    pub fn kill_ring_yank(
10735        &mut self,
10736        _: &KillRingYank,
10737        window: &mut Window,
10738        cx: &mut Context<Self>,
10739    ) {
10740        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10741        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
10742            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
10743                (kill_ring.text().to_string(), kill_ring.metadata_json())
10744            } else {
10745                return;
10746            }
10747        } else {
10748            return;
10749        };
10750        self.do_paste(&text, metadata, false, window, cx);
10751    }
10752
10753    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
10754        self.do_copy(true, cx);
10755    }
10756
10757    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
10758        self.do_copy(false, cx);
10759    }
10760
10761    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
10762        let selections = self.selections.all::<Point>(cx);
10763        let buffer = self.buffer.read(cx).read(cx);
10764        let mut text = String::new();
10765
10766        let mut clipboard_selections = Vec::with_capacity(selections.len());
10767        {
10768            let max_point = buffer.max_point();
10769            let mut is_first = true;
10770            for selection in &selections {
10771                let mut start = selection.start;
10772                let mut end = selection.end;
10773                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10774                if is_entire_line {
10775                    start = Point::new(start.row, 0);
10776                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
10777                }
10778
10779                let mut trimmed_selections = Vec::new();
10780                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
10781                    let row = MultiBufferRow(start.row);
10782                    let first_indent = buffer.indent_size_for_line(row);
10783                    if first_indent.len == 0 || start.column > first_indent.len {
10784                        trimmed_selections.push(start..end);
10785                    } else {
10786                        trimmed_selections.push(
10787                            Point::new(row.0, first_indent.len)
10788                                ..Point::new(row.0, buffer.line_len(row)),
10789                        );
10790                        for row in start.row + 1..=end.row {
10791                            let mut line_len = buffer.line_len(MultiBufferRow(row));
10792                            if row == end.row {
10793                                line_len = end.column;
10794                            }
10795                            if line_len == 0 {
10796                                trimmed_selections
10797                                    .push(Point::new(row, 0)..Point::new(row, line_len));
10798                                continue;
10799                            }
10800                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
10801                            if row_indent_size.len >= first_indent.len {
10802                                trimmed_selections.push(
10803                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
10804                                );
10805                            } else {
10806                                trimmed_selections.clear();
10807                                trimmed_selections.push(start..end);
10808                                break;
10809                            }
10810                        }
10811                    }
10812                } else {
10813                    trimmed_selections.push(start..end);
10814                }
10815
10816                for trimmed_range in trimmed_selections {
10817                    if is_first {
10818                        is_first = false;
10819                    } else {
10820                        text += "\n";
10821                    }
10822                    let mut len = 0;
10823                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
10824                        text.push_str(chunk);
10825                        len += chunk.len();
10826                    }
10827                    clipboard_selections.push(ClipboardSelection {
10828                        len,
10829                        is_entire_line,
10830                        first_line_indent: buffer
10831                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
10832                            .len,
10833                    });
10834                }
10835            }
10836        }
10837
10838        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
10839            text,
10840            clipboard_selections,
10841        ));
10842    }
10843
10844    pub fn do_paste(
10845        &mut self,
10846        text: &String,
10847        clipboard_selections: Option<Vec<ClipboardSelection>>,
10848        handle_entire_lines: bool,
10849        window: &mut Window,
10850        cx: &mut Context<Self>,
10851    ) {
10852        if self.read_only(cx) {
10853            return;
10854        }
10855
10856        let clipboard_text = Cow::Borrowed(text);
10857
10858        self.transact(window, cx, |this, window, cx| {
10859            if let Some(mut clipboard_selections) = clipboard_selections {
10860                let old_selections = this.selections.all::<usize>(cx);
10861                let all_selections_were_entire_line =
10862                    clipboard_selections.iter().all(|s| s.is_entire_line);
10863                let first_selection_indent_column =
10864                    clipboard_selections.first().map(|s| s.first_line_indent);
10865                if clipboard_selections.len() != old_selections.len() {
10866                    clipboard_selections.drain(..);
10867                }
10868                let cursor_offset = this.selections.last::<usize>(cx).head();
10869                let mut auto_indent_on_paste = true;
10870
10871                this.buffer.update(cx, |buffer, cx| {
10872                    let snapshot = buffer.read(cx);
10873                    auto_indent_on_paste = snapshot
10874                        .language_settings_at(cursor_offset, cx)
10875                        .auto_indent_on_paste;
10876
10877                    let mut start_offset = 0;
10878                    let mut edits = Vec::new();
10879                    let mut original_indent_columns = Vec::new();
10880                    for (ix, selection) in old_selections.iter().enumerate() {
10881                        let to_insert;
10882                        let entire_line;
10883                        let original_indent_column;
10884                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
10885                            let end_offset = start_offset + clipboard_selection.len;
10886                            to_insert = &clipboard_text[start_offset..end_offset];
10887                            entire_line = clipboard_selection.is_entire_line;
10888                            start_offset = end_offset + 1;
10889                            original_indent_column = Some(clipboard_selection.first_line_indent);
10890                        } else {
10891                            to_insert = clipboard_text.as_str();
10892                            entire_line = all_selections_were_entire_line;
10893                            original_indent_column = first_selection_indent_column
10894                        }
10895
10896                        // If the corresponding selection was empty when this slice of the
10897                        // clipboard text was written, then the entire line containing the
10898                        // selection was copied. If this selection is also currently empty,
10899                        // then paste the line before the current line of the buffer.
10900                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
10901                            let column = selection.start.to_point(&snapshot).column as usize;
10902                            let line_start = selection.start - column;
10903                            line_start..line_start
10904                        } else {
10905                            selection.range()
10906                        };
10907
10908                        edits.push((range, to_insert));
10909                        original_indent_columns.push(original_indent_column);
10910                    }
10911                    drop(snapshot);
10912
10913                    buffer.edit(
10914                        edits,
10915                        if auto_indent_on_paste {
10916                            Some(AutoindentMode::Block {
10917                                original_indent_columns,
10918                            })
10919                        } else {
10920                            None
10921                        },
10922                        cx,
10923                    );
10924                });
10925
10926                let selections = this.selections.all::<usize>(cx);
10927                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10928                    s.select(selections)
10929                });
10930            } else {
10931                this.insert(&clipboard_text, window, cx);
10932            }
10933        });
10934    }
10935
10936    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
10937        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10938        if let Some(item) = cx.read_from_clipboard() {
10939            let entries = item.entries();
10940
10941            match entries.first() {
10942                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
10943                // of all the pasted entries.
10944                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
10945                    .do_paste(
10946                        clipboard_string.text(),
10947                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
10948                        true,
10949                        window,
10950                        cx,
10951                    ),
10952                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
10953            }
10954        }
10955    }
10956
10957    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
10958        if self.read_only(cx) {
10959            return;
10960        }
10961
10962        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10963
10964        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
10965            if let Some((selections, _)) =
10966                self.selection_history.transaction(transaction_id).cloned()
10967            {
10968                self.change_selections(None, window, cx, |s| {
10969                    s.select_anchors(selections.to_vec());
10970                });
10971            } else {
10972                log::error!(
10973                    "No entry in selection_history found for undo. \
10974                     This may correspond to a bug where undo does not update the selection. \
10975                     If this is occurring, please add details to \
10976                     https://github.com/zed-industries/zed/issues/22692"
10977                );
10978            }
10979            self.request_autoscroll(Autoscroll::fit(), cx);
10980            self.unmark_text(window, cx);
10981            self.refresh_inline_completion(true, false, window, cx);
10982            cx.emit(EditorEvent::Edited { transaction_id });
10983            cx.emit(EditorEvent::TransactionUndone { transaction_id });
10984        }
10985    }
10986
10987    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
10988        if self.read_only(cx) {
10989            return;
10990        }
10991
10992        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10993
10994        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
10995            if let Some((_, Some(selections))) =
10996                self.selection_history.transaction(transaction_id).cloned()
10997            {
10998                self.change_selections(None, window, cx, |s| {
10999                    s.select_anchors(selections.to_vec());
11000                });
11001            } else {
11002                log::error!(
11003                    "No entry in selection_history found for redo. \
11004                     This may correspond to a bug where undo does not update the selection. \
11005                     If this is occurring, please add details to \
11006                     https://github.com/zed-industries/zed/issues/22692"
11007                );
11008            }
11009            self.request_autoscroll(Autoscroll::fit(), cx);
11010            self.unmark_text(window, cx);
11011            self.refresh_inline_completion(true, false, window, cx);
11012            cx.emit(EditorEvent::Edited { transaction_id });
11013        }
11014    }
11015
11016    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11017        self.buffer
11018            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11019    }
11020
11021    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11022        self.buffer
11023            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11024    }
11025
11026    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11027        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11028        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11029            s.move_with(|map, selection| {
11030                let cursor = if selection.is_empty() {
11031                    movement::left(map, selection.start)
11032                } else {
11033                    selection.start
11034                };
11035                selection.collapse_to(cursor, SelectionGoal::None);
11036            });
11037        })
11038    }
11039
11040    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11041        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11042        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11043            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11044        })
11045    }
11046
11047    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11048        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11049        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11050            s.move_with(|map, selection| {
11051                let cursor = if selection.is_empty() {
11052                    movement::right(map, selection.end)
11053                } else {
11054                    selection.end
11055                };
11056                selection.collapse_to(cursor, SelectionGoal::None)
11057            });
11058        })
11059    }
11060
11061    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11062        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11063        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11064            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11065        })
11066    }
11067
11068    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11069        if self.take_rename(true, window, cx).is_some() {
11070            return;
11071        }
11072
11073        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11074            cx.propagate();
11075            return;
11076        }
11077
11078        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11079
11080        let text_layout_details = &self.text_layout_details(window);
11081        let selection_count = self.selections.count();
11082        let first_selection = self.selections.first_anchor();
11083
11084        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11085            s.move_with(|map, selection| {
11086                if !selection.is_empty() {
11087                    selection.goal = SelectionGoal::None;
11088                }
11089                let (cursor, goal) = movement::up(
11090                    map,
11091                    selection.start,
11092                    selection.goal,
11093                    false,
11094                    text_layout_details,
11095                );
11096                selection.collapse_to(cursor, goal);
11097            });
11098        });
11099
11100        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11101        {
11102            cx.propagate();
11103        }
11104    }
11105
11106    pub fn move_up_by_lines(
11107        &mut self,
11108        action: &MoveUpByLines,
11109        window: &mut Window,
11110        cx: &mut Context<Self>,
11111    ) {
11112        if self.take_rename(true, window, cx).is_some() {
11113            return;
11114        }
11115
11116        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11117            cx.propagate();
11118            return;
11119        }
11120
11121        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11122
11123        let text_layout_details = &self.text_layout_details(window);
11124
11125        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11126            s.move_with(|map, selection| {
11127                if !selection.is_empty() {
11128                    selection.goal = SelectionGoal::None;
11129                }
11130                let (cursor, goal) = movement::up_by_rows(
11131                    map,
11132                    selection.start,
11133                    action.lines,
11134                    selection.goal,
11135                    false,
11136                    text_layout_details,
11137                );
11138                selection.collapse_to(cursor, goal);
11139            });
11140        })
11141    }
11142
11143    pub fn move_down_by_lines(
11144        &mut self,
11145        action: &MoveDownByLines,
11146        window: &mut Window,
11147        cx: &mut Context<Self>,
11148    ) {
11149        if self.take_rename(true, window, cx).is_some() {
11150            return;
11151        }
11152
11153        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11154            cx.propagate();
11155            return;
11156        }
11157
11158        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11159
11160        let text_layout_details = &self.text_layout_details(window);
11161
11162        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11163            s.move_with(|map, selection| {
11164                if !selection.is_empty() {
11165                    selection.goal = SelectionGoal::None;
11166                }
11167                let (cursor, goal) = movement::down_by_rows(
11168                    map,
11169                    selection.start,
11170                    action.lines,
11171                    selection.goal,
11172                    false,
11173                    text_layout_details,
11174                );
11175                selection.collapse_to(cursor, goal);
11176            });
11177        })
11178    }
11179
11180    pub fn select_down_by_lines(
11181        &mut self,
11182        action: &SelectDownByLines,
11183        window: &mut Window,
11184        cx: &mut Context<Self>,
11185    ) {
11186        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11187        let text_layout_details = &self.text_layout_details(window);
11188        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11189            s.move_heads_with(|map, head, goal| {
11190                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11191            })
11192        })
11193    }
11194
11195    pub fn select_up_by_lines(
11196        &mut self,
11197        action: &SelectUpByLines,
11198        window: &mut Window,
11199        cx: &mut Context<Self>,
11200    ) {
11201        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11202        let text_layout_details = &self.text_layout_details(window);
11203        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11204            s.move_heads_with(|map, head, goal| {
11205                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11206            })
11207        })
11208    }
11209
11210    pub fn select_page_up(
11211        &mut self,
11212        _: &SelectPageUp,
11213        window: &mut Window,
11214        cx: &mut Context<Self>,
11215    ) {
11216        let Some(row_count) = self.visible_row_count() else {
11217            return;
11218        };
11219
11220        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11221
11222        let text_layout_details = &self.text_layout_details(window);
11223
11224        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11225            s.move_heads_with(|map, head, goal| {
11226                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11227            })
11228        })
11229    }
11230
11231    pub fn move_page_up(
11232        &mut self,
11233        action: &MovePageUp,
11234        window: &mut Window,
11235        cx: &mut Context<Self>,
11236    ) {
11237        if self.take_rename(true, window, cx).is_some() {
11238            return;
11239        }
11240
11241        if self
11242            .context_menu
11243            .borrow_mut()
11244            .as_mut()
11245            .map(|menu| menu.select_first(self.completion_provider.as_deref(), cx))
11246            .unwrap_or(false)
11247        {
11248            return;
11249        }
11250
11251        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11252            cx.propagate();
11253            return;
11254        }
11255
11256        let Some(row_count) = self.visible_row_count() else {
11257            return;
11258        };
11259
11260        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11261
11262        let autoscroll = if action.center_cursor {
11263            Autoscroll::center()
11264        } else {
11265            Autoscroll::fit()
11266        };
11267
11268        let text_layout_details = &self.text_layout_details(window);
11269
11270        self.change_selections(Some(autoscroll), window, cx, |s| {
11271            s.move_with(|map, selection| {
11272                if !selection.is_empty() {
11273                    selection.goal = SelectionGoal::None;
11274                }
11275                let (cursor, goal) = movement::up_by_rows(
11276                    map,
11277                    selection.end,
11278                    row_count,
11279                    selection.goal,
11280                    false,
11281                    text_layout_details,
11282                );
11283                selection.collapse_to(cursor, goal);
11284            });
11285        });
11286    }
11287
11288    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11289        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11290        let text_layout_details = &self.text_layout_details(window);
11291        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11292            s.move_heads_with(|map, head, goal| {
11293                movement::up(map, head, goal, false, text_layout_details)
11294            })
11295        })
11296    }
11297
11298    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11299        self.take_rename(true, window, cx);
11300
11301        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11302            cx.propagate();
11303            return;
11304        }
11305
11306        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11307
11308        let text_layout_details = &self.text_layout_details(window);
11309        let selection_count = self.selections.count();
11310        let first_selection = self.selections.first_anchor();
11311
11312        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11313            s.move_with(|map, selection| {
11314                if !selection.is_empty() {
11315                    selection.goal = SelectionGoal::None;
11316                }
11317                let (cursor, goal) = movement::down(
11318                    map,
11319                    selection.end,
11320                    selection.goal,
11321                    false,
11322                    text_layout_details,
11323                );
11324                selection.collapse_to(cursor, goal);
11325            });
11326        });
11327
11328        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11329        {
11330            cx.propagate();
11331        }
11332    }
11333
11334    pub fn select_page_down(
11335        &mut self,
11336        _: &SelectPageDown,
11337        window: &mut Window,
11338        cx: &mut Context<Self>,
11339    ) {
11340        let Some(row_count) = self.visible_row_count() else {
11341            return;
11342        };
11343
11344        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11345
11346        let text_layout_details = &self.text_layout_details(window);
11347
11348        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11349            s.move_heads_with(|map, head, goal| {
11350                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11351            })
11352        })
11353    }
11354
11355    pub fn move_page_down(
11356        &mut self,
11357        action: &MovePageDown,
11358        window: &mut Window,
11359        cx: &mut Context<Self>,
11360    ) {
11361        if self.take_rename(true, window, cx).is_some() {
11362            return;
11363        }
11364
11365        if self
11366            .context_menu
11367            .borrow_mut()
11368            .as_mut()
11369            .map(|menu| menu.select_last(self.completion_provider.as_deref(), cx))
11370            .unwrap_or(false)
11371        {
11372            return;
11373        }
11374
11375        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11376            cx.propagate();
11377            return;
11378        }
11379
11380        let Some(row_count) = self.visible_row_count() else {
11381            return;
11382        };
11383
11384        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11385
11386        let autoscroll = if action.center_cursor {
11387            Autoscroll::center()
11388        } else {
11389            Autoscroll::fit()
11390        };
11391
11392        let text_layout_details = &self.text_layout_details(window);
11393        self.change_selections(Some(autoscroll), window, cx, |s| {
11394            s.move_with(|map, selection| {
11395                if !selection.is_empty() {
11396                    selection.goal = SelectionGoal::None;
11397                }
11398                let (cursor, goal) = movement::down_by_rows(
11399                    map,
11400                    selection.end,
11401                    row_count,
11402                    selection.goal,
11403                    false,
11404                    text_layout_details,
11405                );
11406                selection.collapse_to(cursor, goal);
11407            });
11408        });
11409    }
11410
11411    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11412        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11413        let text_layout_details = &self.text_layout_details(window);
11414        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11415            s.move_heads_with(|map, head, goal| {
11416                movement::down(map, head, goal, false, text_layout_details)
11417            })
11418        });
11419    }
11420
11421    pub fn context_menu_first(
11422        &mut self,
11423        _: &ContextMenuFirst,
11424        _window: &mut Window,
11425        cx: &mut Context<Self>,
11426    ) {
11427        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11428            context_menu.select_first(self.completion_provider.as_deref(), cx);
11429        }
11430    }
11431
11432    pub fn context_menu_prev(
11433        &mut self,
11434        _: &ContextMenuPrevious,
11435        _window: &mut Window,
11436        cx: &mut Context<Self>,
11437    ) {
11438        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11439            context_menu.select_prev(self.completion_provider.as_deref(), cx);
11440        }
11441    }
11442
11443    pub fn context_menu_next(
11444        &mut self,
11445        _: &ContextMenuNext,
11446        _window: &mut Window,
11447        cx: &mut Context<Self>,
11448    ) {
11449        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11450            context_menu.select_next(self.completion_provider.as_deref(), cx);
11451        }
11452    }
11453
11454    pub fn context_menu_last(
11455        &mut self,
11456        _: &ContextMenuLast,
11457        _window: &mut Window,
11458        cx: &mut Context<Self>,
11459    ) {
11460        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11461            context_menu.select_last(self.completion_provider.as_deref(), cx);
11462        }
11463    }
11464
11465    pub fn move_to_previous_word_start(
11466        &mut self,
11467        _: &MoveToPreviousWordStart,
11468        window: &mut Window,
11469        cx: &mut Context<Self>,
11470    ) {
11471        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11472        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11473            s.move_cursors_with(|map, head, _| {
11474                (
11475                    movement::previous_word_start(map, head),
11476                    SelectionGoal::None,
11477                )
11478            });
11479        })
11480    }
11481
11482    pub fn move_to_previous_subword_start(
11483        &mut self,
11484        _: &MoveToPreviousSubwordStart,
11485        window: &mut Window,
11486        cx: &mut Context<Self>,
11487    ) {
11488        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11489        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11490            s.move_cursors_with(|map, head, _| {
11491                (
11492                    movement::previous_subword_start(map, head),
11493                    SelectionGoal::None,
11494                )
11495            });
11496        })
11497    }
11498
11499    pub fn select_to_previous_word_start(
11500        &mut self,
11501        _: &SelectToPreviousWordStart,
11502        window: &mut Window,
11503        cx: &mut Context<Self>,
11504    ) {
11505        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11506        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11507            s.move_heads_with(|map, head, _| {
11508                (
11509                    movement::previous_word_start(map, head),
11510                    SelectionGoal::None,
11511                )
11512            });
11513        })
11514    }
11515
11516    pub fn select_to_previous_subword_start(
11517        &mut self,
11518        _: &SelectToPreviousSubwordStart,
11519        window: &mut Window,
11520        cx: &mut Context<Self>,
11521    ) {
11522        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11523        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11524            s.move_heads_with(|map, head, _| {
11525                (
11526                    movement::previous_subword_start(map, head),
11527                    SelectionGoal::None,
11528                )
11529            });
11530        })
11531    }
11532
11533    pub fn delete_to_previous_word_start(
11534        &mut self,
11535        action: &DeleteToPreviousWordStart,
11536        window: &mut Window,
11537        cx: &mut Context<Self>,
11538    ) {
11539        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11540        self.transact(window, cx, |this, window, cx| {
11541            this.select_autoclose_pair(window, cx);
11542            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11543                s.move_with(|map, selection| {
11544                    if selection.is_empty() {
11545                        let cursor = if action.ignore_newlines {
11546                            movement::previous_word_start(map, selection.head())
11547                        } else {
11548                            movement::previous_word_start_or_newline(map, selection.head())
11549                        };
11550                        selection.set_head(cursor, SelectionGoal::None);
11551                    }
11552                });
11553            });
11554            this.insert("", window, cx);
11555        });
11556    }
11557
11558    pub fn delete_to_previous_subword_start(
11559        &mut self,
11560        _: &DeleteToPreviousSubwordStart,
11561        window: &mut Window,
11562        cx: &mut Context<Self>,
11563    ) {
11564        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11565        self.transact(window, cx, |this, window, cx| {
11566            this.select_autoclose_pair(window, cx);
11567            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11568                s.move_with(|map, selection| {
11569                    if selection.is_empty() {
11570                        let cursor = movement::previous_subword_start(map, selection.head());
11571                        selection.set_head(cursor, SelectionGoal::None);
11572                    }
11573                });
11574            });
11575            this.insert("", window, cx);
11576        });
11577    }
11578
11579    pub fn move_to_next_word_end(
11580        &mut self,
11581        _: &MoveToNextWordEnd,
11582        window: &mut Window,
11583        cx: &mut Context<Self>,
11584    ) {
11585        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11586        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11587            s.move_cursors_with(|map, head, _| {
11588                (movement::next_word_end(map, head), SelectionGoal::None)
11589            });
11590        })
11591    }
11592
11593    pub fn move_to_next_subword_end(
11594        &mut self,
11595        _: &MoveToNextSubwordEnd,
11596        window: &mut Window,
11597        cx: &mut Context<Self>,
11598    ) {
11599        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11600        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11601            s.move_cursors_with(|map, head, _| {
11602                (movement::next_subword_end(map, head), SelectionGoal::None)
11603            });
11604        })
11605    }
11606
11607    pub fn select_to_next_word_end(
11608        &mut self,
11609        _: &SelectToNextWordEnd,
11610        window: &mut Window,
11611        cx: &mut Context<Self>,
11612    ) {
11613        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11614        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11615            s.move_heads_with(|map, head, _| {
11616                (movement::next_word_end(map, head), SelectionGoal::None)
11617            });
11618        })
11619    }
11620
11621    pub fn select_to_next_subword_end(
11622        &mut self,
11623        _: &SelectToNextSubwordEnd,
11624        window: &mut Window,
11625        cx: &mut Context<Self>,
11626    ) {
11627        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11628        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11629            s.move_heads_with(|map, head, _| {
11630                (movement::next_subword_end(map, head), SelectionGoal::None)
11631            });
11632        })
11633    }
11634
11635    pub fn delete_to_next_word_end(
11636        &mut self,
11637        action: &DeleteToNextWordEnd,
11638        window: &mut Window,
11639        cx: &mut Context<Self>,
11640    ) {
11641        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11642        self.transact(window, cx, |this, window, cx| {
11643            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11644                s.move_with(|map, selection| {
11645                    if selection.is_empty() {
11646                        let cursor = if action.ignore_newlines {
11647                            movement::next_word_end(map, selection.head())
11648                        } else {
11649                            movement::next_word_end_or_newline(map, selection.head())
11650                        };
11651                        selection.set_head(cursor, SelectionGoal::None);
11652                    }
11653                });
11654            });
11655            this.insert("", window, cx);
11656        });
11657    }
11658
11659    pub fn delete_to_next_subword_end(
11660        &mut self,
11661        _: &DeleteToNextSubwordEnd,
11662        window: &mut Window,
11663        cx: &mut Context<Self>,
11664    ) {
11665        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11666        self.transact(window, cx, |this, window, cx| {
11667            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11668                s.move_with(|map, selection| {
11669                    if selection.is_empty() {
11670                        let cursor = movement::next_subword_end(map, selection.head());
11671                        selection.set_head(cursor, SelectionGoal::None);
11672                    }
11673                });
11674            });
11675            this.insert("", window, cx);
11676        });
11677    }
11678
11679    pub fn move_to_beginning_of_line(
11680        &mut self,
11681        action: &MoveToBeginningOfLine,
11682        window: &mut Window,
11683        cx: &mut Context<Self>,
11684    ) {
11685        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11686        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11687            s.move_cursors_with(|map, head, _| {
11688                (
11689                    movement::indented_line_beginning(
11690                        map,
11691                        head,
11692                        action.stop_at_soft_wraps,
11693                        action.stop_at_indent,
11694                    ),
11695                    SelectionGoal::None,
11696                )
11697            });
11698        })
11699    }
11700
11701    pub fn select_to_beginning_of_line(
11702        &mut self,
11703        action: &SelectToBeginningOfLine,
11704        window: &mut Window,
11705        cx: &mut Context<Self>,
11706    ) {
11707        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11708        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11709            s.move_heads_with(|map, head, _| {
11710                (
11711                    movement::indented_line_beginning(
11712                        map,
11713                        head,
11714                        action.stop_at_soft_wraps,
11715                        action.stop_at_indent,
11716                    ),
11717                    SelectionGoal::None,
11718                )
11719            });
11720        });
11721    }
11722
11723    pub fn delete_to_beginning_of_line(
11724        &mut self,
11725        action: &DeleteToBeginningOfLine,
11726        window: &mut Window,
11727        cx: &mut Context<Self>,
11728    ) {
11729        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11730        self.transact(window, cx, |this, window, cx| {
11731            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11732                s.move_with(|_, selection| {
11733                    selection.reversed = true;
11734                });
11735            });
11736
11737            this.select_to_beginning_of_line(
11738                &SelectToBeginningOfLine {
11739                    stop_at_soft_wraps: false,
11740                    stop_at_indent: action.stop_at_indent,
11741                },
11742                window,
11743                cx,
11744            );
11745            this.backspace(&Backspace, window, cx);
11746        });
11747    }
11748
11749    pub fn move_to_end_of_line(
11750        &mut self,
11751        action: &MoveToEndOfLine,
11752        window: &mut Window,
11753        cx: &mut Context<Self>,
11754    ) {
11755        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11756        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11757            s.move_cursors_with(|map, head, _| {
11758                (
11759                    movement::line_end(map, head, action.stop_at_soft_wraps),
11760                    SelectionGoal::None,
11761                )
11762            });
11763        })
11764    }
11765
11766    pub fn select_to_end_of_line(
11767        &mut self,
11768        action: &SelectToEndOfLine,
11769        window: &mut Window,
11770        cx: &mut Context<Self>,
11771    ) {
11772        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11773        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11774            s.move_heads_with(|map, head, _| {
11775                (
11776                    movement::line_end(map, head, action.stop_at_soft_wraps),
11777                    SelectionGoal::None,
11778                )
11779            });
11780        })
11781    }
11782
11783    pub fn delete_to_end_of_line(
11784        &mut self,
11785        _: &DeleteToEndOfLine,
11786        window: &mut Window,
11787        cx: &mut Context<Self>,
11788    ) {
11789        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11790        self.transact(window, cx, |this, window, cx| {
11791            this.select_to_end_of_line(
11792                &SelectToEndOfLine {
11793                    stop_at_soft_wraps: false,
11794                },
11795                window,
11796                cx,
11797            );
11798            this.delete(&Delete, window, cx);
11799        });
11800    }
11801
11802    pub fn cut_to_end_of_line(
11803        &mut self,
11804        _: &CutToEndOfLine,
11805        window: &mut Window,
11806        cx: &mut Context<Self>,
11807    ) {
11808        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11809        self.transact(window, cx, |this, window, cx| {
11810            this.select_to_end_of_line(
11811                &SelectToEndOfLine {
11812                    stop_at_soft_wraps: false,
11813                },
11814                window,
11815                cx,
11816            );
11817            this.cut(&Cut, window, cx);
11818        });
11819    }
11820
11821    pub fn move_to_start_of_paragraph(
11822        &mut self,
11823        _: &MoveToStartOfParagraph,
11824        window: &mut Window,
11825        cx: &mut Context<Self>,
11826    ) {
11827        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11828            cx.propagate();
11829            return;
11830        }
11831        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11832        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11833            s.move_with(|map, selection| {
11834                selection.collapse_to(
11835                    movement::start_of_paragraph(map, selection.head(), 1),
11836                    SelectionGoal::None,
11837                )
11838            });
11839        })
11840    }
11841
11842    pub fn move_to_end_of_paragraph(
11843        &mut self,
11844        _: &MoveToEndOfParagraph,
11845        window: &mut Window,
11846        cx: &mut Context<Self>,
11847    ) {
11848        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11849            cx.propagate();
11850            return;
11851        }
11852        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11853        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11854            s.move_with(|map, selection| {
11855                selection.collapse_to(
11856                    movement::end_of_paragraph(map, selection.head(), 1),
11857                    SelectionGoal::None,
11858                )
11859            });
11860        })
11861    }
11862
11863    pub fn select_to_start_of_paragraph(
11864        &mut self,
11865        _: &SelectToStartOfParagraph,
11866        window: &mut Window,
11867        cx: &mut Context<Self>,
11868    ) {
11869        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11870            cx.propagate();
11871            return;
11872        }
11873        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11874        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11875            s.move_heads_with(|map, head, _| {
11876                (
11877                    movement::start_of_paragraph(map, head, 1),
11878                    SelectionGoal::None,
11879                )
11880            });
11881        })
11882    }
11883
11884    pub fn select_to_end_of_paragraph(
11885        &mut self,
11886        _: &SelectToEndOfParagraph,
11887        window: &mut Window,
11888        cx: &mut Context<Self>,
11889    ) {
11890        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11891            cx.propagate();
11892            return;
11893        }
11894        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11895        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11896            s.move_heads_with(|map, head, _| {
11897                (
11898                    movement::end_of_paragraph(map, head, 1),
11899                    SelectionGoal::None,
11900                )
11901            });
11902        })
11903    }
11904
11905    pub fn move_to_start_of_excerpt(
11906        &mut self,
11907        _: &MoveToStartOfExcerpt,
11908        window: &mut Window,
11909        cx: &mut Context<Self>,
11910    ) {
11911        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11912            cx.propagate();
11913            return;
11914        }
11915        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11916        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11917            s.move_with(|map, selection| {
11918                selection.collapse_to(
11919                    movement::start_of_excerpt(
11920                        map,
11921                        selection.head(),
11922                        workspace::searchable::Direction::Prev,
11923                    ),
11924                    SelectionGoal::None,
11925                )
11926            });
11927        })
11928    }
11929
11930    pub fn move_to_start_of_next_excerpt(
11931        &mut self,
11932        _: &MoveToStartOfNextExcerpt,
11933        window: &mut Window,
11934        cx: &mut Context<Self>,
11935    ) {
11936        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11937            cx.propagate();
11938            return;
11939        }
11940
11941        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11942            s.move_with(|map, selection| {
11943                selection.collapse_to(
11944                    movement::start_of_excerpt(
11945                        map,
11946                        selection.head(),
11947                        workspace::searchable::Direction::Next,
11948                    ),
11949                    SelectionGoal::None,
11950                )
11951            });
11952        })
11953    }
11954
11955    pub fn move_to_end_of_excerpt(
11956        &mut self,
11957        _: &MoveToEndOfExcerpt,
11958        window: &mut Window,
11959        cx: &mut Context<Self>,
11960    ) {
11961        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11962            cx.propagate();
11963            return;
11964        }
11965        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11966        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11967            s.move_with(|map, selection| {
11968                selection.collapse_to(
11969                    movement::end_of_excerpt(
11970                        map,
11971                        selection.head(),
11972                        workspace::searchable::Direction::Next,
11973                    ),
11974                    SelectionGoal::None,
11975                )
11976            });
11977        })
11978    }
11979
11980    pub fn move_to_end_of_previous_excerpt(
11981        &mut self,
11982        _: &MoveToEndOfPreviousExcerpt,
11983        window: &mut Window,
11984        cx: &mut Context<Self>,
11985    ) {
11986        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11987            cx.propagate();
11988            return;
11989        }
11990        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11991        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11992            s.move_with(|map, selection| {
11993                selection.collapse_to(
11994                    movement::end_of_excerpt(
11995                        map,
11996                        selection.head(),
11997                        workspace::searchable::Direction::Prev,
11998                    ),
11999                    SelectionGoal::None,
12000                )
12001            });
12002        })
12003    }
12004
12005    pub fn select_to_start_of_excerpt(
12006        &mut self,
12007        _: &SelectToStartOfExcerpt,
12008        window: &mut Window,
12009        cx: &mut Context<Self>,
12010    ) {
12011        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12012            cx.propagate();
12013            return;
12014        }
12015        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12016        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12017            s.move_heads_with(|map, head, _| {
12018                (
12019                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12020                    SelectionGoal::None,
12021                )
12022            });
12023        })
12024    }
12025
12026    pub fn select_to_start_of_next_excerpt(
12027        &mut self,
12028        _: &SelectToStartOfNextExcerpt,
12029        window: &mut Window,
12030        cx: &mut Context<Self>,
12031    ) {
12032        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12033            cx.propagate();
12034            return;
12035        }
12036        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12037        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12038            s.move_heads_with(|map, head, _| {
12039                (
12040                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12041                    SelectionGoal::None,
12042                )
12043            });
12044        })
12045    }
12046
12047    pub fn select_to_end_of_excerpt(
12048        &mut self,
12049        _: &SelectToEndOfExcerpt,
12050        window: &mut Window,
12051        cx: &mut Context<Self>,
12052    ) {
12053        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12054            cx.propagate();
12055            return;
12056        }
12057        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12058        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12059            s.move_heads_with(|map, head, _| {
12060                (
12061                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12062                    SelectionGoal::None,
12063                )
12064            });
12065        })
12066    }
12067
12068    pub fn select_to_end_of_previous_excerpt(
12069        &mut self,
12070        _: &SelectToEndOfPreviousExcerpt,
12071        window: &mut Window,
12072        cx: &mut Context<Self>,
12073    ) {
12074        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12075            cx.propagate();
12076            return;
12077        }
12078        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12079        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12080            s.move_heads_with(|map, head, _| {
12081                (
12082                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12083                    SelectionGoal::None,
12084                )
12085            });
12086        })
12087    }
12088
12089    pub fn move_to_beginning(
12090        &mut self,
12091        _: &MoveToBeginning,
12092        window: &mut Window,
12093        cx: &mut Context<Self>,
12094    ) {
12095        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12096            cx.propagate();
12097            return;
12098        }
12099        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12100        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12101            s.select_ranges(vec![0..0]);
12102        });
12103    }
12104
12105    pub fn select_to_beginning(
12106        &mut self,
12107        _: &SelectToBeginning,
12108        window: &mut Window,
12109        cx: &mut Context<Self>,
12110    ) {
12111        let mut selection = self.selections.last::<Point>(cx);
12112        selection.set_head(Point::zero(), SelectionGoal::None);
12113        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12114        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12115            s.select(vec![selection]);
12116        });
12117    }
12118
12119    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12120        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12121            cx.propagate();
12122            return;
12123        }
12124        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12125        let cursor = self.buffer.read(cx).read(cx).len();
12126        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12127            s.select_ranges(vec![cursor..cursor])
12128        });
12129    }
12130
12131    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12132        self.nav_history = nav_history;
12133    }
12134
12135    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12136        self.nav_history.as_ref()
12137    }
12138
12139    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12140        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12141    }
12142
12143    fn push_to_nav_history(
12144        &mut self,
12145        cursor_anchor: Anchor,
12146        new_position: Option<Point>,
12147        is_deactivate: bool,
12148        cx: &mut Context<Self>,
12149    ) {
12150        if let Some(nav_history) = self.nav_history.as_mut() {
12151            let buffer = self.buffer.read(cx).read(cx);
12152            let cursor_position = cursor_anchor.to_point(&buffer);
12153            let scroll_state = self.scroll_manager.anchor();
12154            let scroll_top_row = scroll_state.top_row(&buffer);
12155            drop(buffer);
12156
12157            if let Some(new_position) = new_position {
12158                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12159                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12160                    return;
12161                }
12162            }
12163
12164            nav_history.push(
12165                Some(NavigationData {
12166                    cursor_anchor,
12167                    cursor_position,
12168                    scroll_anchor: scroll_state,
12169                    scroll_top_row,
12170                }),
12171                cx,
12172            );
12173            cx.emit(EditorEvent::PushedToNavHistory {
12174                anchor: cursor_anchor,
12175                is_deactivate,
12176            })
12177        }
12178    }
12179
12180    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12181        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12182        let buffer = self.buffer.read(cx).snapshot(cx);
12183        let mut selection = self.selections.first::<usize>(cx);
12184        selection.set_head(buffer.len(), SelectionGoal::None);
12185        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12186            s.select(vec![selection]);
12187        });
12188    }
12189
12190    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12191        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12192        let end = self.buffer.read(cx).read(cx).len();
12193        self.change_selections(None, window, cx, |s| {
12194            s.select_ranges(vec![0..end]);
12195        });
12196    }
12197
12198    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12199        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12200        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12201        let mut selections = self.selections.all::<Point>(cx);
12202        let max_point = display_map.buffer_snapshot.max_point();
12203        for selection in &mut selections {
12204            let rows = selection.spanned_rows(true, &display_map);
12205            selection.start = Point::new(rows.start.0, 0);
12206            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12207            selection.reversed = false;
12208        }
12209        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12210            s.select(selections);
12211        });
12212    }
12213
12214    pub fn split_selection_into_lines(
12215        &mut self,
12216        _: &SplitSelectionIntoLines,
12217        window: &mut Window,
12218        cx: &mut Context<Self>,
12219    ) {
12220        let selections = self
12221            .selections
12222            .all::<Point>(cx)
12223            .into_iter()
12224            .map(|selection| selection.start..selection.end)
12225            .collect::<Vec<_>>();
12226        self.unfold_ranges(&selections, true, true, cx);
12227
12228        let mut new_selection_ranges = Vec::new();
12229        {
12230            let buffer = self.buffer.read(cx).read(cx);
12231            for selection in selections {
12232                for row in selection.start.row..selection.end.row {
12233                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12234                    new_selection_ranges.push(cursor..cursor);
12235                }
12236
12237                let is_multiline_selection = selection.start.row != selection.end.row;
12238                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12239                // so this action feels more ergonomic when paired with other selection operations
12240                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12241                if !should_skip_last {
12242                    new_selection_ranges.push(selection.end..selection.end);
12243                }
12244            }
12245        }
12246        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12247            s.select_ranges(new_selection_ranges);
12248        });
12249    }
12250
12251    pub fn add_selection_above(
12252        &mut self,
12253        _: &AddSelectionAbove,
12254        window: &mut Window,
12255        cx: &mut Context<Self>,
12256    ) {
12257        self.add_selection(true, window, cx);
12258    }
12259
12260    pub fn add_selection_below(
12261        &mut self,
12262        _: &AddSelectionBelow,
12263        window: &mut Window,
12264        cx: &mut Context<Self>,
12265    ) {
12266        self.add_selection(false, window, cx);
12267    }
12268
12269    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12270        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12271
12272        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12273        let mut selections = self.selections.all::<Point>(cx);
12274        let text_layout_details = self.text_layout_details(window);
12275        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
12276            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
12277            let range = oldest_selection.display_range(&display_map).sorted();
12278
12279            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12280            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12281            let positions = start_x.min(end_x)..start_x.max(end_x);
12282
12283            selections.clear();
12284            let mut stack = Vec::new();
12285            for row in range.start.row().0..=range.end.row().0 {
12286                if let Some(selection) = self.selections.build_columnar_selection(
12287                    &display_map,
12288                    DisplayRow(row),
12289                    &positions,
12290                    oldest_selection.reversed,
12291                    &text_layout_details,
12292                ) {
12293                    stack.push(selection.id);
12294                    selections.push(selection);
12295                }
12296            }
12297
12298            if above {
12299                stack.reverse();
12300            }
12301
12302            AddSelectionsState { above, stack }
12303        });
12304
12305        let last_added_selection = *state.stack.last().unwrap();
12306        let mut new_selections = Vec::new();
12307        if above == state.above {
12308            let end_row = if above {
12309                DisplayRow(0)
12310            } else {
12311                display_map.max_point().row()
12312            };
12313
12314            'outer: for selection in selections {
12315                if selection.id == last_added_selection {
12316                    let range = selection.display_range(&display_map).sorted();
12317                    debug_assert_eq!(range.start.row(), range.end.row());
12318                    let mut row = range.start.row();
12319                    let positions =
12320                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12321                            px(start)..px(end)
12322                        } else {
12323                            let start_x =
12324                                display_map.x_for_display_point(range.start, &text_layout_details);
12325                            let end_x =
12326                                display_map.x_for_display_point(range.end, &text_layout_details);
12327                            start_x.min(end_x)..start_x.max(end_x)
12328                        };
12329
12330                    while row != end_row {
12331                        if above {
12332                            row.0 -= 1;
12333                        } else {
12334                            row.0 += 1;
12335                        }
12336
12337                        if let Some(new_selection) = self.selections.build_columnar_selection(
12338                            &display_map,
12339                            row,
12340                            &positions,
12341                            selection.reversed,
12342                            &text_layout_details,
12343                        ) {
12344                            state.stack.push(new_selection.id);
12345                            if above {
12346                                new_selections.push(new_selection);
12347                                new_selections.push(selection);
12348                            } else {
12349                                new_selections.push(selection);
12350                                new_selections.push(new_selection);
12351                            }
12352
12353                            continue 'outer;
12354                        }
12355                    }
12356                }
12357
12358                new_selections.push(selection);
12359            }
12360        } else {
12361            new_selections = selections;
12362            new_selections.retain(|s| s.id != last_added_selection);
12363            state.stack.pop();
12364        }
12365
12366        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12367            s.select(new_selections);
12368        });
12369        if state.stack.len() > 1 {
12370            self.add_selections_state = Some(state);
12371        }
12372    }
12373
12374    fn select_match_ranges(
12375        &mut self,
12376        range: Range<usize>,
12377        reversed: bool,
12378        replace_newest: bool,
12379        auto_scroll: Option<Autoscroll>,
12380        window: &mut Window,
12381        cx: &mut Context<Editor>,
12382    ) {
12383        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
12384        self.change_selections(auto_scroll, window, cx, |s| {
12385            if replace_newest {
12386                s.delete(s.newest_anchor().id);
12387            }
12388            if reversed {
12389                s.insert_range(range.end..range.start);
12390            } else {
12391                s.insert_range(range);
12392            }
12393        });
12394    }
12395
12396    pub fn select_next_match_internal(
12397        &mut self,
12398        display_map: &DisplaySnapshot,
12399        replace_newest: bool,
12400        autoscroll: Option<Autoscroll>,
12401        window: &mut Window,
12402        cx: &mut Context<Self>,
12403    ) -> Result<()> {
12404        let buffer = &display_map.buffer_snapshot;
12405        let mut selections = self.selections.all::<usize>(cx);
12406        if let Some(mut select_next_state) = self.select_next_state.take() {
12407            let query = &select_next_state.query;
12408            if !select_next_state.done {
12409                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12410                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12411                let mut next_selected_range = None;
12412
12413                let bytes_after_last_selection =
12414                    buffer.bytes_in_range(last_selection.end..buffer.len());
12415                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
12416                let query_matches = query
12417                    .stream_find_iter(bytes_after_last_selection)
12418                    .map(|result| (last_selection.end, result))
12419                    .chain(
12420                        query
12421                            .stream_find_iter(bytes_before_first_selection)
12422                            .map(|result| (0, result)),
12423                    );
12424
12425                for (start_offset, query_match) in query_matches {
12426                    let query_match = query_match.unwrap(); // can only fail due to I/O
12427                    let offset_range =
12428                        start_offset + query_match.start()..start_offset + query_match.end();
12429                    let display_range = offset_range.start.to_display_point(display_map)
12430                        ..offset_range.end.to_display_point(display_map);
12431
12432                    if !select_next_state.wordwise
12433                        || (!movement::is_inside_word(display_map, display_range.start)
12434                            && !movement::is_inside_word(display_map, display_range.end))
12435                    {
12436                        // TODO: This is n^2, because we might check all the selections
12437                        if !selections
12438                            .iter()
12439                            .any(|selection| selection.range().overlaps(&offset_range))
12440                        {
12441                            next_selected_range = Some(offset_range);
12442                            break;
12443                        }
12444                    }
12445                }
12446
12447                if let Some(next_selected_range) = next_selected_range {
12448                    self.select_match_ranges(
12449                        next_selected_range,
12450                        last_selection.reversed,
12451                        replace_newest,
12452                        autoscroll,
12453                        window,
12454                        cx,
12455                    );
12456                } else {
12457                    select_next_state.done = true;
12458                }
12459            }
12460
12461            self.select_next_state = Some(select_next_state);
12462        } else {
12463            let mut only_carets = true;
12464            let mut same_text_selected = true;
12465            let mut selected_text = None;
12466
12467            let mut selections_iter = selections.iter().peekable();
12468            while let Some(selection) = selections_iter.next() {
12469                if selection.start != selection.end {
12470                    only_carets = false;
12471                }
12472
12473                if same_text_selected {
12474                    if selected_text.is_none() {
12475                        selected_text =
12476                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12477                    }
12478
12479                    if let Some(next_selection) = selections_iter.peek() {
12480                        if next_selection.range().len() == selection.range().len() {
12481                            let next_selected_text = buffer
12482                                .text_for_range(next_selection.range())
12483                                .collect::<String>();
12484                            if Some(next_selected_text) != selected_text {
12485                                same_text_selected = false;
12486                                selected_text = None;
12487                            }
12488                        } else {
12489                            same_text_selected = false;
12490                            selected_text = None;
12491                        }
12492                    }
12493                }
12494            }
12495
12496            if only_carets {
12497                for selection in &mut selections {
12498                    let word_range = movement::surrounding_word(
12499                        display_map,
12500                        selection.start.to_display_point(display_map),
12501                    );
12502                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
12503                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
12504                    selection.goal = SelectionGoal::None;
12505                    selection.reversed = false;
12506                    self.select_match_ranges(
12507                        selection.start..selection.end,
12508                        selection.reversed,
12509                        replace_newest,
12510                        autoscroll,
12511                        window,
12512                        cx,
12513                    );
12514                }
12515
12516                if selections.len() == 1 {
12517                    let selection = selections
12518                        .last()
12519                        .expect("ensured that there's only one selection");
12520                    let query = buffer
12521                        .text_for_range(selection.start..selection.end)
12522                        .collect::<String>();
12523                    let is_empty = query.is_empty();
12524                    let select_state = SelectNextState {
12525                        query: AhoCorasick::new(&[query])?,
12526                        wordwise: true,
12527                        done: is_empty,
12528                    };
12529                    self.select_next_state = Some(select_state);
12530                } else {
12531                    self.select_next_state = None;
12532                }
12533            } else if let Some(selected_text) = selected_text {
12534                self.select_next_state = Some(SelectNextState {
12535                    query: AhoCorasick::new(&[selected_text])?,
12536                    wordwise: false,
12537                    done: false,
12538                });
12539                self.select_next_match_internal(
12540                    display_map,
12541                    replace_newest,
12542                    autoscroll,
12543                    window,
12544                    cx,
12545                )?;
12546            }
12547        }
12548        Ok(())
12549    }
12550
12551    pub fn select_all_matches(
12552        &mut self,
12553        _action: &SelectAllMatches,
12554        window: &mut Window,
12555        cx: &mut Context<Self>,
12556    ) -> Result<()> {
12557        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12558
12559        self.push_to_selection_history();
12560        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12561
12562        self.select_next_match_internal(&display_map, false, None, window, cx)?;
12563        let Some(select_next_state) = self.select_next_state.as_mut() else {
12564            return Ok(());
12565        };
12566        if select_next_state.done {
12567            return Ok(());
12568        }
12569
12570        let mut new_selections = Vec::new();
12571
12572        let reversed = self.selections.oldest::<usize>(cx).reversed;
12573        let buffer = &display_map.buffer_snapshot;
12574        let query_matches = select_next_state
12575            .query
12576            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
12577
12578        for query_match in query_matches.into_iter() {
12579            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
12580            let offset_range = if reversed {
12581                query_match.end()..query_match.start()
12582            } else {
12583                query_match.start()..query_match.end()
12584            };
12585            let display_range = offset_range.start.to_display_point(&display_map)
12586                ..offset_range.end.to_display_point(&display_map);
12587
12588            if !select_next_state.wordwise
12589                || (!movement::is_inside_word(&display_map, display_range.start)
12590                    && !movement::is_inside_word(&display_map, display_range.end))
12591            {
12592                new_selections.push(offset_range.start..offset_range.end);
12593            }
12594        }
12595
12596        select_next_state.done = true;
12597        self.unfold_ranges(&new_selections.clone(), false, false, cx);
12598        self.change_selections(None, window, cx, |selections| {
12599            selections.select_ranges(new_selections)
12600        });
12601
12602        Ok(())
12603    }
12604
12605    pub fn select_next(
12606        &mut self,
12607        action: &SelectNext,
12608        window: &mut Window,
12609        cx: &mut Context<Self>,
12610    ) -> Result<()> {
12611        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12612        self.push_to_selection_history();
12613        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12614        self.select_next_match_internal(
12615            &display_map,
12616            action.replace_newest,
12617            Some(Autoscroll::newest()),
12618            window,
12619            cx,
12620        )?;
12621        Ok(())
12622    }
12623
12624    pub fn select_previous(
12625        &mut self,
12626        action: &SelectPrevious,
12627        window: &mut Window,
12628        cx: &mut Context<Self>,
12629    ) -> Result<()> {
12630        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12631        self.push_to_selection_history();
12632        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12633        let buffer = &display_map.buffer_snapshot;
12634        let mut selections = self.selections.all::<usize>(cx);
12635        if let Some(mut select_prev_state) = self.select_prev_state.take() {
12636            let query = &select_prev_state.query;
12637            if !select_prev_state.done {
12638                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12639                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12640                let mut next_selected_range = None;
12641                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
12642                let bytes_before_last_selection =
12643                    buffer.reversed_bytes_in_range(0..last_selection.start);
12644                let bytes_after_first_selection =
12645                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
12646                let query_matches = query
12647                    .stream_find_iter(bytes_before_last_selection)
12648                    .map(|result| (last_selection.start, result))
12649                    .chain(
12650                        query
12651                            .stream_find_iter(bytes_after_first_selection)
12652                            .map(|result| (buffer.len(), result)),
12653                    );
12654                for (end_offset, query_match) in query_matches {
12655                    let query_match = query_match.unwrap(); // can only fail due to I/O
12656                    let offset_range =
12657                        end_offset - query_match.end()..end_offset - query_match.start();
12658                    let display_range = offset_range.start.to_display_point(&display_map)
12659                        ..offset_range.end.to_display_point(&display_map);
12660
12661                    if !select_prev_state.wordwise
12662                        || (!movement::is_inside_word(&display_map, display_range.start)
12663                            && !movement::is_inside_word(&display_map, display_range.end))
12664                    {
12665                        next_selected_range = Some(offset_range);
12666                        break;
12667                    }
12668                }
12669
12670                if let Some(next_selected_range) = next_selected_range {
12671                    self.select_match_ranges(
12672                        next_selected_range,
12673                        last_selection.reversed,
12674                        action.replace_newest,
12675                        Some(Autoscroll::newest()),
12676                        window,
12677                        cx,
12678                    );
12679                } else {
12680                    select_prev_state.done = true;
12681                }
12682            }
12683
12684            self.select_prev_state = Some(select_prev_state);
12685        } else {
12686            let mut only_carets = true;
12687            let mut same_text_selected = true;
12688            let mut selected_text = None;
12689
12690            let mut selections_iter = selections.iter().peekable();
12691            while let Some(selection) = selections_iter.next() {
12692                if selection.start != selection.end {
12693                    only_carets = false;
12694                }
12695
12696                if same_text_selected {
12697                    if selected_text.is_none() {
12698                        selected_text =
12699                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12700                    }
12701
12702                    if let Some(next_selection) = selections_iter.peek() {
12703                        if next_selection.range().len() == selection.range().len() {
12704                            let next_selected_text = buffer
12705                                .text_for_range(next_selection.range())
12706                                .collect::<String>();
12707                            if Some(next_selected_text) != selected_text {
12708                                same_text_selected = false;
12709                                selected_text = None;
12710                            }
12711                        } else {
12712                            same_text_selected = false;
12713                            selected_text = None;
12714                        }
12715                    }
12716                }
12717            }
12718
12719            if only_carets {
12720                for selection in &mut selections {
12721                    let word_range = movement::surrounding_word(
12722                        &display_map,
12723                        selection.start.to_display_point(&display_map),
12724                    );
12725                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
12726                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
12727                    selection.goal = SelectionGoal::None;
12728                    selection.reversed = false;
12729                    self.select_match_ranges(
12730                        selection.start..selection.end,
12731                        selection.reversed,
12732                        action.replace_newest,
12733                        Some(Autoscroll::newest()),
12734                        window,
12735                        cx,
12736                    );
12737                }
12738                if selections.len() == 1 {
12739                    let selection = selections
12740                        .last()
12741                        .expect("ensured that there's only one selection");
12742                    let query = buffer
12743                        .text_for_range(selection.start..selection.end)
12744                        .collect::<String>();
12745                    let is_empty = query.is_empty();
12746                    let select_state = SelectNextState {
12747                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
12748                        wordwise: true,
12749                        done: is_empty,
12750                    };
12751                    self.select_prev_state = Some(select_state);
12752                } else {
12753                    self.select_prev_state = None;
12754                }
12755            } else if let Some(selected_text) = selected_text {
12756                self.select_prev_state = Some(SelectNextState {
12757                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
12758                    wordwise: false,
12759                    done: false,
12760                });
12761                self.select_previous(action, window, cx)?;
12762            }
12763        }
12764        Ok(())
12765    }
12766
12767    pub fn find_next_match(
12768        &mut self,
12769        _: &FindNextMatch,
12770        window: &mut Window,
12771        cx: &mut Context<Self>,
12772    ) -> Result<()> {
12773        let selections = self.selections.disjoint_anchors();
12774        match selections.first() {
12775            Some(first) if selections.len() >= 2 => {
12776                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12777                    s.select_ranges([first.range()]);
12778                });
12779            }
12780            _ => self.select_next(
12781                &SelectNext {
12782                    replace_newest: true,
12783                },
12784                window,
12785                cx,
12786            )?,
12787        }
12788        Ok(())
12789    }
12790
12791    pub fn find_previous_match(
12792        &mut self,
12793        _: &FindPreviousMatch,
12794        window: &mut Window,
12795        cx: &mut Context<Self>,
12796    ) -> Result<()> {
12797        let selections = self.selections.disjoint_anchors();
12798        match selections.last() {
12799            Some(last) if selections.len() >= 2 => {
12800                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12801                    s.select_ranges([last.range()]);
12802                });
12803            }
12804            _ => self.select_previous(
12805                &SelectPrevious {
12806                    replace_newest: true,
12807                },
12808                window,
12809                cx,
12810            )?,
12811        }
12812        Ok(())
12813    }
12814
12815    pub fn toggle_comments(
12816        &mut self,
12817        action: &ToggleComments,
12818        window: &mut Window,
12819        cx: &mut Context<Self>,
12820    ) {
12821        if self.read_only(cx) {
12822            return;
12823        }
12824        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12825        let text_layout_details = &self.text_layout_details(window);
12826        self.transact(window, cx, |this, window, cx| {
12827            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
12828            let mut edits = Vec::new();
12829            let mut selection_edit_ranges = Vec::new();
12830            let mut last_toggled_row = None;
12831            let snapshot = this.buffer.read(cx).read(cx);
12832            let empty_str: Arc<str> = Arc::default();
12833            let mut suffixes_inserted = Vec::new();
12834            let ignore_indent = action.ignore_indent;
12835
12836            fn comment_prefix_range(
12837                snapshot: &MultiBufferSnapshot,
12838                row: MultiBufferRow,
12839                comment_prefix: &str,
12840                comment_prefix_whitespace: &str,
12841                ignore_indent: bool,
12842            ) -> Range<Point> {
12843                let indent_size = if ignore_indent {
12844                    0
12845                } else {
12846                    snapshot.indent_size_for_line(row).len
12847                };
12848
12849                let start = Point::new(row.0, indent_size);
12850
12851                let mut line_bytes = snapshot
12852                    .bytes_in_range(start..snapshot.max_point())
12853                    .flatten()
12854                    .copied();
12855
12856                // If this line currently begins with the line comment prefix, then record
12857                // the range containing the prefix.
12858                if line_bytes
12859                    .by_ref()
12860                    .take(comment_prefix.len())
12861                    .eq(comment_prefix.bytes())
12862                {
12863                    // Include any whitespace that matches the comment prefix.
12864                    let matching_whitespace_len = line_bytes
12865                        .zip(comment_prefix_whitespace.bytes())
12866                        .take_while(|(a, b)| a == b)
12867                        .count() as u32;
12868                    let end = Point::new(
12869                        start.row,
12870                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
12871                    );
12872                    start..end
12873                } else {
12874                    start..start
12875                }
12876            }
12877
12878            fn comment_suffix_range(
12879                snapshot: &MultiBufferSnapshot,
12880                row: MultiBufferRow,
12881                comment_suffix: &str,
12882                comment_suffix_has_leading_space: bool,
12883            ) -> Range<Point> {
12884                let end = Point::new(row.0, snapshot.line_len(row));
12885                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
12886
12887                let mut line_end_bytes = snapshot
12888                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
12889                    .flatten()
12890                    .copied();
12891
12892                let leading_space_len = if suffix_start_column > 0
12893                    && line_end_bytes.next() == Some(b' ')
12894                    && comment_suffix_has_leading_space
12895                {
12896                    1
12897                } else {
12898                    0
12899                };
12900
12901                // If this line currently begins with the line comment prefix, then record
12902                // the range containing the prefix.
12903                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
12904                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
12905                    start..end
12906                } else {
12907                    end..end
12908                }
12909            }
12910
12911            // TODO: Handle selections that cross excerpts
12912            for selection in &mut selections {
12913                let start_column = snapshot
12914                    .indent_size_for_line(MultiBufferRow(selection.start.row))
12915                    .len;
12916                let language = if let Some(language) =
12917                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
12918                {
12919                    language
12920                } else {
12921                    continue;
12922                };
12923
12924                selection_edit_ranges.clear();
12925
12926                // If multiple selections contain a given row, avoid processing that
12927                // row more than once.
12928                let mut start_row = MultiBufferRow(selection.start.row);
12929                if last_toggled_row == Some(start_row) {
12930                    start_row = start_row.next_row();
12931                }
12932                let end_row =
12933                    if selection.end.row > selection.start.row && selection.end.column == 0 {
12934                        MultiBufferRow(selection.end.row - 1)
12935                    } else {
12936                        MultiBufferRow(selection.end.row)
12937                    };
12938                last_toggled_row = Some(end_row);
12939
12940                if start_row > end_row {
12941                    continue;
12942                }
12943
12944                // If the language has line comments, toggle those.
12945                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
12946
12947                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
12948                if ignore_indent {
12949                    full_comment_prefixes = full_comment_prefixes
12950                        .into_iter()
12951                        .map(|s| Arc::from(s.trim_end()))
12952                        .collect();
12953                }
12954
12955                if !full_comment_prefixes.is_empty() {
12956                    let first_prefix = full_comment_prefixes
12957                        .first()
12958                        .expect("prefixes is non-empty");
12959                    let prefix_trimmed_lengths = full_comment_prefixes
12960                        .iter()
12961                        .map(|p| p.trim_end_matches(' ').len())
12962                        .collect::<SmallVec<[usize; 4]>>();
12963
12964                    let mut all_selection_lines_are_comments = true;
12965
12966                    for row in start_row.0..=end_row.0 {
12967                        let row = MultiBufferRow(row);
12968                        if start_row < end_row && snapshot.is_line_blank(row) {
12969                            continue;
12970                        }
12971
12972                        let prefix_range = full_comment_prefixes
12973                            .iter()
12974                            .zip(prefix_trimmed_lengths.iter().copied())
12975                            .map(|(prefix, trimmed_prefix_len)| {
12976                                comment_prefix_range(
12977                                    snapshot.deref(),
12978                                    row,
12979                                    &prefix[..trimmed_prefix_len],
12980                                    &prefix[trimmed_prefix_len..],
12981                                    ignore_indent,
12982                                )
12983                            })
12984                            .max_by_key(|range| range.end.column - range.start.column)
12985                            .expect("prefixes is non-empty");
12986
12987                        if prefix_range.is_empty() {
12988                            all_selection_lines_are_comments = false;
12989                        }
12990
12991                        selection_edit_ranges.push(prefix_range);
12992                    }
12993
12994                    if all_selection_lines_are_comments {
12995                        edits.extend(
12996                            selection_edit_ranges
12997                                .iter()
12998                                .cloned()
12999                                .map(|range| (range, empty_str.clone())),
13000                        );
13001                    } else {
13002                        let min_column = selection_edit_ranges
13003                            .iter()
13004                            .map(|range| range.start.column)
13005                            .min()
13006                            .unwrap_or(0);
13007                        edits.extend(selection_edit_ranges.iter().map(|range| {
13008                            let position = Point::new(range.start.row, min_column);
13009                            (position..position, first_prefix.clone())
13010                        }));
13011                    }
13012                } else if let Some((full_comment_prefix, comment_suffix)) =
13013                    language.block_comment_delimiters()
13014                {
13015                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13016                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13017                    let prefix_range = comment_prefix_range(
13018                        snapshot.deref(),
13019                        start_row,
13020                        comment_prefix,
13021                        comment_prefix_whitespace,
13022                        ignore_indent,
13023                    );
13024                    let suffix_range = comment_suffix_range(
13025                        snapshot.deref(),
13026                        end_row,
13027                        comment_suffix.trim_start_matches(' '),
13028                        comment_suffix.starts_with(' '),
13029                    );
13030
13031                    if prefix_range.is_empty() || suffix_range.is_empty() {
13032                        edits.push((
13033                            prefix_range.start..prefix_range.start,
13034                            full_comment_prefix.clone(),
13035                        ));
13036                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13037                        suffixes_inserted.push((end_row, comment_suffix.len()));
13038                    } else {
13039                        edits.push((prefix_range, empty_str.clone()));
13040                        edits.push((suffix_range, empty_str.clone()));
13041                    }
13042                } else {
13043                    continue;
13044                }
13045            }
13046
13047            drop(snapshot);
13048            this.buffer.update(cx, |buffer, cx| {
13049                buffer.edit(edits, None, cx);
13050            });
13051
13052            // Adjust selections so that they end before any comment suffixes that
13053            // were inserted.
13054            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13055            let mut selections = this.selections.all::<Point>(cx);
13056            let snapshot = this.buffer.read(cx).read(cx);
13057            for selection in &mut selections {
13058                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13059                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13060                        Ordering::Less => {
13061                            suffixes_inserted.next();
13062                            continue;
13063                        }
13064                        Ordering::Greater => break,
13065                        Ordering::Equal => {
13066                            if selection.end.column == snapshot.line_len(row) {
13067                                if selection.is_empty() {
13068                                    selection.start.column -= suffix_len as u32;
13069                                }
13070                                selection.end.column -= suffix_len as u32;
13071                            }
13072                            break;
13073                        }
13074                    }
13075                }
13076            }
13077
13078            drop(snapshot);
13079            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13080                s.select(selections)
13081            });
13082
13083            let selections = this.selections.all::<Point>(cx);
13084            let selections_on_single_row = selections.windows(2).all(|selections| {
13085                selections[0].start.row == selections[1].start.row
13086                    && selections[0].end.row == selections[1].end.row
13087                    && selections[0].start.row == selections[0].end.row
13088            });
13089            let selections_selecting = selections
13090                .iter()
13091                .any(|selection| selection.start != selection.end);
13092            let advance_downwards = action.advance_downwards
13093                && selections_on_single_row
13094                && !selections_selecting
13095                && !matches!(this.mode, EditorMode::SingleLine { .. });
13096
13097            if advance_downwards {
13098                let snapshot = this.buffer.read(cx).snapshot(cx);
13099
13100                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13101                    s.move_cursors_with(|display_snapshot, display_point, _| {
13102                        let mut point = display_point.to_point(display_snapshot);
13103                        point.row += 1;
13104                        point = snapshot.clip_point(point, Bias::Left);
13105                        let display_point = point.to_display_point(display_snapshot);
13106                        let goal = SelectionGoal::HorizontalPosition(
13107                            display_snapshot
13108                                .x_for_display_point(display_point, text_layout_details)
13109                                .into(),
13110                        );
13111                        (display_point, goal)
13112                    })
13113                });
13114            }
13115        });
13116    }
13117
13118    pub fn select_enclosing_symbol(
13119        &mut self,
13120        _: &SelectEnclosingSymbol,
13121        window: &mut Window,
13122        cx: &mut Context<Self>,
13123    ) {
13124        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13125
13126        let buffer = self.buffer.read(cx).snapshot(cx);
13127        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13128
13129        fn update_selection(
13130            selection: &Selection<usize>,
13131            buffer_snap: &MultiBufferSnapshot,
13132        ) -> Option<Selection<usize>> {
13133            let cursor = selection.head();
13134            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13135            for symbol in symbols.iter().rev() {
13136                let start = symbol.range.start.to_offset(buffer_snap);
13137                let end = symbol.range.end.to_offset(buffer_snap);
13138                let new_range = start..end;
13139                if start < selection.start || end > selection.end {
13140                    return Some(Selection {
13141                        id: selection.id,
13142                        start: new_range.start,
13143                        end: new_range.end,
13144                        goal: SelectionGoal::None,
13145                        reversed: selection.reversed,
13146                    });
13147                }
13148            }
13149            None
13150        }
13151
13152        let mut selected_larger_symbol = false;
13153        let new_selections = old_selections
13154            .iter()
13155            .map(|selection| match update_selection(selection, &buffer) {
13156                Some(new_selection) => {
13157                    if new_selection.range() != selection.range() {
13158                        selected_larger_symbol = true;
13159                    }
13160                    new_selection
13161                }
13162                None => selection.clone(),
13163            })
13164            .collect::<Vec<_>>();
13165
13166        if selected_larger_symbol {
13167            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13168                s.select(new_selections);
13169            });
13170        }
13171    }
13172
13173    pub fn select_larger_syntax_node(
13174        &mut self,
13175        _: &SelectLargerSyntaxNode,
13176        window: &mut Window,
13177        cx: &mut Context<Self>,
13178    ) {
13179        let Some(visible_row_count) = self.visible_row_count() else {
13180            return;
13181        };
13182        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13183        if old_selections.is_empty() {
13184            return;
13185        }
13186
13187        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13188
13189        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13190        let buffer = self.buffer.read(cx).snapshot(cx);
13191
13192        let mut selected_larger_node = false;
13193        let mut new_selections = old_selections
13194            .iter()
13195            .map(|selection| {
13196                let old_range = selection.start..selection.end;
13197
13198                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13199                    // manually select word at selection
13200                    if ["string_content", "inline"].contains(&node.kind()) {
13201                        let word_range = {
13202                            let display_point = buffer
13203                                .offset_to_point(old_range.start)
13204                                .to_display_point(&display_map);
13205                            let Range { start, end } =
13206                                movement::surrounding_word(&display_map, display_point);
13207                            start.to_point(&display_map).to_offset(&buffer)
13208                                ..end.to_point(&display_map).to_offset(&buffer)
13209                        };
13210                        // ignore if word is already selected
13211                        if !word_range.is_empty() && old_range != word_range {
13212                            let last_word_range = {
13213                                let display_point = buffer
13214                                    .offset_to_point(old_range.end)
13215                                    .to_display_point(&display_map);
13216                                let Range { start, end } =
13217                                    movement::surrounding_word(&display_map, display_point);
13218                                start.to_point(&display_map).to_offset(&buffer)
13219                                    ..end.to_point(&display_map).to_offset(&buffer)
13220                            };
13221                            // only select word if start and end point belongs to same word
13222                            if word_range == last_word_range {
13223                                selected_larger_node = true;
13224                                return Selection {
13225                                    id: selection.id,
13226                                    start: word_range.start,
13227                                    end: word_range.end,
13228                                    goal: SelectionGoal::None,
13229                                    reversed: selection.reversed,
13230                                };
13231                            }
13232                        }
13233                    }
13234                }
13235
13236                let mut new_range = old_range.clone();
13237                while let Some((_node, containing_range)) =
13238                    buffer.syntax_ancestor(new_range.clone())
13239                {
13240                    new_range = match containing_range {
13241                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13242                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13243                    };
13244                    if !display_map.intersects_fold(new_range.start)
13245                        && !display_map.intersects_fold(new_range.end)
13246                    {
13247                        break;
13248                    }
13249                }
13250
13251                selected_larger_node |= new_range != old_range;
13252                Selection {
13253                    id: selection.id,
13254                    start: new_range.start,
13255                    end: new_range.end,
13256                    goal: SelectionGoal::None,
13257                    reversed: selection.reversed,
13258                }
13259            })
13260            .collect::<Vec<_>>();
13261
13262        if !selected_larger_node {
13263            return; // don't put this call in the history
13264        }
13265
13266        // scroll based on transformation done to the last selection created by the user
13267        let (last_old, last_new) = old_selections
13268            .last()
13269            .zip(new_selections.last().cloned())
13270            .expect("old_selections isn't empty");
13271
13272        // revert selection
13273        let is_selection_reversed = {
13274            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13275            new_selections.last_mut().expect("checked above").reversed =
13276                should_newest_selection_be_reversed;
13277            should_newest_selection_be_reversed
13278        };
13279
13280        if selected_larger_node {
13281            self.select_syntax_node_history.disable_clearing = true;
13282            self.change_selections(None, window, cx, |s| {
13283                s.select(new_selections.clone());
13284            });
13285            self.select_syntax_node_history.disable_clearing = false;
13286        }
13287
13288        let start_row = last_new.start.to_display_point(&display_map).row().0;
13289        let end_row = last_new.end.to_display_point(&display_map).row().0;
13290        let selection_height = end_row - start_row + 1;
13291        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13292
13293        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13294        let scroll_behavior = if fits_on_the_screen {
13295            self.request_autoscroll(Autoscroll::fit(), cx);
13296            SelectSyntaxNodeScrollBehavior::FitSelection
13297        } else if is_selection_reversed {
13298            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13299            SelectSyntaxNodeScrollBehavior::CursorTop
13300        } else {
13301            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13302            SelectSyntaxNodeScrollBehavior::CursorBottom
13303        };
13304
13305        self.select_syntax_node_history.push((
13306            old_selections,
13307            scroll_behavior,
13308            is_selection_reversed,
13309        ));
13310    }
13311
13312    pub fn select_smaller_syntax_node(
13313        &mut self,
13314        _: &SelectSmallerSyntaxNode,
13315        window: &mut Window,
13316        cx: &mut Context<Self>,
13317    ) {
13318        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13319
13320        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13321            self.select_syntax_node_history.pop()
13322        {
13323            if let Some(selection) = selections.last_mut() {
13324                selection.reversed = is_selection_reversed;
13325            }
13326
13327            self.select_syntax_node_history.disable_clearing = true;
13328            self.change_selections(None, window, cx, |s| {
13329                s.select(selections.to_vec());
13330            });
13331            self.select_syntax_node_history.disable_clearing = false;
13332
13333            match scroll_behavior {
13334                SelectSyntaxNodeScrollBehavior::CursorTop => {
13335                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13336                }
13337                SelectSyntaxNodeScrollBehavior::FitSelection => {
13338                    self.request_autoscroll(Autoscroll::fit(), cx);
13339                }
13340                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13341                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13342                }
13343            }
13344        }
13345    }
13346
13347    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13348        if !EditorSettings::get_global(cx).gutter.runnables {
13349            self.clear_tasks();
13350            return Task::ready(());
13351        }
13352        let project = self.project.as_ref().map(Entity::downgrade);
13353        let task_sources = self.lsp_task_sources(cx);
13354        cx.spawn_in(window, async move |editor, cx| {
13355            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13356            let Some(project) = project.and_then(|p| p.upgrade()) else {
13357                return;
13358            };
13359            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13360                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13361            }) else {
13362                return;
13363            };
13364
13365            let hide_runnables = project
13366                .update(cx, |project, cx| {
13367                    // Do not display any test indicators in non-dev server remote projects.
13368                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13369                })
13370                .unwrap_or(true);
13371            if hide_runnables {
13372                return;
13373            }
13374            let new_rows =
13375                cx.background_spawn({
13376                    let snapshot = display_snapshot.clone();
13377                    async move {
13378                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13379                    }
13380                })
13381                    .await;
13382            let Ok(lsp_tasks) =
13383                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13384            else {
13385                return;
13386            };
13387            let lsp_tasks = lsp_tasks.await;
13388
13389            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
13390                lsp_tasks
13391                    .into_iter()
13392                    .flat_map(|(kind, tasks)| {
13393                        tasks.into_iter().filter_map(move |(location, task)| {
13394                            Some((kind.clone(), location?, task))
13395                        })
13396                    })
13397                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
13398                        let buffer = location.target.buffer;
13399                        let buffer_snapshot = buffer.read(cx).snapshot();
13400                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
13401                            |(excerpt_id, snapshot, _)| {
13402                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
13403                                    display_snapshot
13404                                        .buffer_snapshot
13405                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
13406                                } else {
13407                                    None
13408                                }
13409                            },
13410                        );
13411                        if let Some(offset) = offset {
13412                            let task_buffer_range =
13413                                location.target.range.to_point(&buffer_snapshot);
13414                            let context_buffer_range =
13415                                task_buffer_range.to_offset(&buffer_snapshot);
13416                            let context_range = BufferOffset(context_buffer_range.start)
13417                                ..BufferOffset(context_buffer_range.end);
13418
13419                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
13420                                .or_insert_with(|| RunnableTasks {
13421                                    templates: Vec::new(),
13422                                    offset,
13423                                    column: task_buffer_range.start.column,
13424                                    extra_variables: HashMap::default(),
13425                                    context_range,
13426                                })
13427                                .templates
13428                                .push((kind, task.original_task().clone()));
13429                        }
13430
13431                        acc
13432                    })
13433            }) else {
13434                return;
13435            };
13436
13437            let rows = Self::runnable_rows(project, display_snapshot, new_rows, cx.clone());
13438            editor
13439                .update(cx, |editor, _| {
13440                    editor.clear_tasks();
13441                    for (key, mut value) in rows {
13442                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
13443                            value.templates.extend(lsp_tasks.templates);
13444                        }
13445
13446                        editor.insert_tasks(key, value);
13447                    }
13448                    for (key, value) in lsp_tasks_by_rows {
13449                        editor.insert_tasks(key, value);
13450                    }
13451                })
13452                .ok();
13453        })
13454    }
13455    fn fetch_runnable_ranges(
13456        snapshot: &DisplaySnapshot,
13457        range: Range<Anchor>,
13458    ) -> Vec<language::RunnableRange> {
13459        snapshot.buffer_snapshot.runnable_ranges(range).collect()
13460    }
13461
13462    fn runnable_rows(
13463        project: Entity<Project>,
13464        snapshot: DisplaySnapshot,
13465        runnable_ranges: Vec<RunnableRange>,
13466        mut cx: AsyncWindowContext,
13467    ) -> Vec<((BufferId, BufferRow), RunnableTasks)> {
13468        runnable_ranges
13469            .into_iter()
13470            .filter_map(|mut runnable| {
13471                let tasks = cx
13472                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
13473                    .ok()?;
13474                if tasks.is_empty() {
13475                    return None;
13476                }
13477
13478                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
13479
13480                let row = snapshot
13481                    .buffer_snapshot
13482                    .buffer_line_for_row(MultiBufferRow(point.row))?
13483                    .1
13484                    .start
13485                    .row;
13486
13487                let context_range =
13488                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
13489                Some((
13490                    (runnable.buffer_id, row),
13491                    RunnableTasks {
13492                        templates: tasks,
13493                        offset: snapshot
13494                            .buffer_snapshot
13495                            .anchor_before(runnable.run_range.start),
13496                        context_range,
13497                        column: point.column,
13498                        extra_variables: runnable.extra_captures,
13499                    },
13500                ))
13501            })
13502            .collect()
13503    }
13504
13505    fn templates_with_tags(
13506        project: &Entity<Project>,
13507        runnable: &mut Runnable,
13508        cx: &mut App,
13509    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
13510        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
13511            let (worktree_id, file) = project
13512                .buffer_for_id(runnable.buffer, cx)
13513                .and_then(|buffer| buffer.read(cx).file())
13514                .map(|file| (file.worktree_id(cx), file.clone()))
13515                .unzip();
13516
13517            (
13518                project.task_store().read(cx).task_inventory().cloned(),
13519                worktree_id,
13520                file,
13521            )
13522        });
13523
13524        let mut templates_with_tags = mem::take(&mut runnable.tags)
13525            .into_iter()
13526            .flat_map(|RunnableTag(tag)| {
13527                inventory
13528                    .as_ref()
13529                    .into_iter()
13530                    .flat_map(|inventory| {
13531                        inventory.read(cx).list_tasks(
13532                            file.clone(),
13533                            Some(runnable.language.clone()),
13534                            worktree_id,
13535                            cx,
13536                        )
13537                    })
13538                    .filter(move |(_, template)| {
13539                        template.tags.iter().any(|source_tag| source_tag == &tag)
13540                    })
13541            })
13542            .sorted_by_key(|(kind, _)| kind.to_owned())
13543            .collect::<Vec<_>>();
13544        if let Some((leading_tag_source, _)) = templates_with_tags.first() {
13545            // Strongest source wins; if we have worktree tag binding, prefer that to
13546            // global and language bindings;
13547            // if we have a global binding, prefer that to language binding.
13548            let first_mismatch = templates_with_tags
13549                .iter()
13550                .position(|(tag_source, _)| tag_source != leading_tag_source);
13551            if let Some(index) = first_mismatch {
13552                templates_with_tags.truncate(index);
13553            }
13554        }
13555
13556        templates_with_tags
13557    }
13558
13559    pub fn move_to_enclosing_bracket(
13560        &mut self,
13561        _: &MoveToEnclosingBracket,
13562        window: &mut Window,
13563        cx: &mut Context<Self>,
13564    ) {
13565        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13566        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13567            s.move_offsets_with(|snapshot, selection| {
13568                let Some(enclosing_bracket_ranges) =
13569                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
13570                else {
13571                    return;
13572                };
13573
13574                let mut best_length = usize::MAX;
13575                let mut best_inside = false;
13576                let mut best_in_bracket_range = false;
13577                let mut best_destination = None;
13578                for (open, close) in enclosing_bracket_ranges {
13579                    let close = close.to_inclusive();
13580                    let length = close.end() - open.start;
13581                    let inside = selection.start >= open.end && selection.end <= *close.start();
13582                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
13583                        || close.contains(&selection.head());
13584
13585                    // If best is next to a bracket and current isn't, skip
13586                    if !in_bracket_range && best_in_bracket_range {
13587                        continue;
13588                    }
13589
13590                    // Prefer smaller lengths unless best is inside and current isn't
13591                    if length > best_length && (best_inside || !inside) {
13592                        continue;
13593                    }
13594
13595                    best_length = length;
13596                    best_inside = inside;
13597                    best_in_bracket_range = in_bracket_range;
13598                    best_destination = Some(
13599                        if close.contains(&selection.start) && close.contains(&selection.end) {
13600                            if inside { open.end } else { open.start }
13601                        } else if inside {
13602                            *close.start()
13603                        } else {
13604                            *close.end()
13605                        },
13606                    );
13607                }
13608
13609                if let Some(destination) = best_destination {
13610                    selection.collapse_to(destination, SelectionGoal::None);
13611                }
13612            })
13613        });
13614    }
13615
13616    pub fn undo_selection(
13617        &mut self,
13618        _: &UndoSelection,
13619        window: &mut Window,
13620        cx: &mut Context<Self>,
13621    ) {
13622        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13623        self.end_selection(window, cx);
13624        self.selection_history.mode = SelectionHistoryMode::Undoing;
13625        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
13626            self.change_selections(None, window, cx, |s| {
13627                s.select_anchors(entry.selections.to_vec())
13628            });
13629            self.select_next_state = entry.select_next_state;
13630            self.select_prev_state = entry.select_prev_state;
13631            self.add_selections_state = entry.add_selections_state;
13632            self.request_autoscroll(Autoscroll::newest(), cx);
13633        }
13634        self.selection_history.mode = SelectionHistoryMode::Normal;
13635    }
13636
13637    pub fn redo_selection(
13638        &mut self,
13639        _: &RedoSelection,
13640        window: &mut Window,
13641        cx: &mut Context<Self>,
13642    ) {
13643        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13644        self.end_selection(window, cx);
13645        self.selection_history.mode = SelectionHistoryMode::Redoing;
13646        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
13647            self.change_selections(None, window, cx, |s| {
13648                s.select_anchors(entry.selections.to_vec())
13649            });
13650            self.select_next_state = entry.select_next_state;
13651            self.select_prev_state = entry.select_prev_state;
13652            self.add_selections_state = entry.add_selections_state;
13653            self.request_autoscroll(Autoscroll::newest(), cx);
13654        }
13655        self.selection_history.mode = SelectionHistoryMode::Normal;
13656    }
13657
13658    pub fn expand_excerpts(
13659        &mut self,
13660        action: &ExpandExcerpts,
13661        _: &mut Window,
13662        cx: &mut Context<Self>,
13663    ) {
13664        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
13665    }
13666
13667    pub fn expand_excerpts_down(
13668        &mut self,
13669        action: &ExpandExcerptsDown,
13670        _: &mut Window,
13671        cx: &mut Context<Self>,
13672    ) {
13673        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
13674    }
13675
13676    pub fn expand_excerpts_up(
13677        &mut self,
13678        action: &ExpandExcerptsUp,
13679        _: &mut Window,
13680        cx: &mut Context<Self>,
13681    ) {
13682        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
13683    }
13684
13685    pub fn expand_excerpts_for_direction(
13686        &mut self,
13687        lines: u32,
13688        direction: ExpandExcerptDirection,
13689
13690        cx: &mut Context<Self>,
13691    ) {
13692        let selections = self.selections.disjoint_anchors();
13693
13694        let lines = if lines == 0 {
13695            EditorSettings::get_global(cx).expand_excerpt_lines
13696        } else {
13697            lines
13698        };
13699
13700        self.buffer.update(cx, |buffer, cx| {
13701            let snapshot = buffer.snapshot(cx);
13702            let mut excerpt_ids = selections
13703                .iter()
13704                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
13705                .collect::<Vec<_>>();
13706            excerpt_ids.sort();
13707            excerpt_ids.dedup();
13708            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
13709        })
13710    }
13711
13712    pub fn expand_excerpt(
13713        &mut self,
13714        excerpt: ExcerptId,
13715        direction: ExpandExcerptDirection,
13716        window: &mut Window,
13717        cx: &mut Context<Self>,
13718    ) {
13719        let current_scroll_position = self.scroll_position(cx);
13720        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
13721        let mut should_scroll_up = false;
13722
13723        if direction == ExpandExcerptDirection::Down {
13724            let multi_buffer = self.buffer.read(cx);
13725            let snapshot = multi_buffer.snapshot(cx);
13726            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
13727                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
13728                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
13729                        let buffer_snapshot = buffer.read(cx).snapshot();
13730                        let excerpt_end_row =
13731                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
13732                        let last_row = buffer_snapshot.max_point().row;
13733                        let lines_below = last_row.saturating_sub(excerpt_end_row);
13734                        should_scroll_up = lines_below >= lines_to_expand;
13735                    }
13736                }
13737            }
13738        }
13739
13740        self.buffer.update(cx, |buffer, cx| {
13741            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
13742        });
13743
13744        if should_scroll_up {
13745            let new_scroll_position =
13746                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
13747            self.set_scroll_position(new_scroll_position, window, cx);
13748        }
13749    }
13750
13751    pub fn go_to_singleton_buffer_point(
13752        &mut self,
13753        point: Point,
13754        window: &mut Window,
13755        cx: &mut Context<Self>,
13756    ) {
13757        self.go_to_singleton_buffer_range(point..point, window, cx);
13758    }
13759
13760    pub fn go_to_singleton_buffer_range(
13761        &mut self,
13762        range: Range<Point>,
13763        window: &mut Window,
13764        cx: &mut Context<Self>,
13765    ) {
13766        let multibuffer = self.buffer().read(cx);
13767        let Some(buffer) = multibuffer.as_singleton() else {
13768            return;
13769        };
13770        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
13771            return;
13772        };
13773        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
13774            return;
13775        };
13776        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
13777            s.select_anchor_ranges([start..end])
13778        });
13779    }
13780
13781    pub fn go_to_diagnostic(
13782        &mut self,
13783        _: &GoToDiagnostic,
13784        window: &mut Window,
13785        cx: &mut Context<Self>,
13786    ) {
13787        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13788        self.go_to_diagnostic_impl(Direction::Next, window, cx)
13789    }
13790
13791    pub fn go_to_prev_diagnostic(
13792        &mut self,
13793        _: &GoToPreviousDiagnostic,
13794        window: &mut Window,
13795        cx: &mut Context<Self>,
13796    ) {
13797        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13798        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
13799    }
13800
13801    pub fn go_to_diagnostic_impl(
13802        &mut self,
13803        direction: Direction,
13804        window: &mut Window,
13805        cx: &mut Context<Self>,
13806    ) {
13807        let buffer = self.buffer.read(cx).snapshot(cx);
13808        let selection = self.selections.newest::<usize>(cx);
13809
13810        let mut active_group_id = None;
13811        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
13812            if active_group.active_range.start.to_offset(&buffer) == selection.start {
13813                active_group_id = Some(active_group.group_id);
13814            }
13815        }
13816
13817        fn filtered(
13818            snapshot: EditorSnapshot,
13819            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
13820        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
13821            diagnostics
13822                .filter(|entry| entry.range.start != entry.range.end)
13823                .filter(|entry| !entry.diagnostic.is_unnecessary)
13824                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
13825        }
13826
13827        let snapshot = self.snapshot(window, cx);
13828        let before = filtered(
13829            snapshot.clone(),
13830            buffer
13831                .diagnostics_in_range(0..selection.start)
13832                .filter(|entry| entry.range.start <= selection.start),
13833        );
13834        let after = filtered(
13835            snapshot,
13836            buffer
13837                .diagnostics_in_range(selection.start..buffer.len())
13838                .filter(|entry| entry.range.start >= selection.start),
13839        );
13840
13841        let mut found: Option<DiagnosticEntry<usize>> = None;
13842        if direction == Direction::Prev {
13843            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
13844            {
13845                for diagnostic in prev_diagnostics.into_iter().rev() {
13846                    if diagnostic.range.start != selection.start
13847                        || active_group_id
13848                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
13849                    {
13850                        found = Some(diagnostic);
13851                        break 'outer;
13852                    }
13853                }
13854            }
13855        } else {
13856            for diagnostic in after.chain(before) {
13857                if diagnostic.range.start != selection.start
13858                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
13859                {
13860                    found = Some(diagnostic);
13861                    break;
13862                }
13863            }
13864        }
13865        let Some(next_diagnostic) = found else {
13866            return;
13867        };
13868
13869        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
13870            return;
13871        };
13872        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13873            s.select_ranges(vec![
13874                next_diagnostic.range.start..next_diagnostic.range.start,
13875            ])
13876        });
13877        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
13878        self.refresh_inline_completion(false, true, window, cx);
13879    }
13880
13881    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
13882        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13883        let snapshot = self.snapshot(window, cx);
13884        let selection = self.selections.newest::<Point>(cx);
13885        self.go_to_hunk_before_or_after_position(
13886            &snapshot,
13887            selection.head(),
13888            Direction::Next,
13889            window,
13890            cx,
13891        );
13892    }
13893
13894    pub fn go_to_hunk_before_or_after_position(
13895        &mut self,
13896        snapshot: &EditorSnapshot,
13897        position: Point,
13898        direction: Direction,
13899        window: &mut Window,
13900        cx: &mut Context<Editor>,
13901    ) {
13902        let row = if direction == Direction::Next {
13903            self.hunk_after_position(snapshot, position)
13904                .map(|hunk| hunk.row_range.start)
13905        } else {
13906            self.hunk_before_position(snapshot, position)
13907        };
13908
13909        if let Some(row) = row {
13910            let destination = Point::new(row.0, 0);
13911            let autoscroll = Autoscroll::center();
13912
13913            self.unfold_ranges(&[destination..destination], false, false, cx);
13914            self.change_selections(Some(autoscroll), window, cx, |s| {
13915                s.select_ranges([destination..destination]);
13916            });
13917        }
13918    }
13919
13920    fn hunk_after_position(
13921        &mut self,
13922        snapshot: &EditorSnapshot,
13923        position: Point,
13924    ) -> Option<MultiBufferDiffHunk> {
13925        snapshot
13926            .buffer_snapshot
13927            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
13928            .find(|hunk| hunk.row_range.start.0 > position.row)
13929            .or_else(|| {
13930                snapshot
13931                    .buffer_snapshot
13932                    .diff_hunks_in_range(Point::zero()..position)
13933                    .find(|hunk| hunk.row_range.end.0 < position.row)
13934            })
13935    }
13936
13937    fn go_to_prev_hunk(
13938        &mut self,
13939        _: &GoToPreviousHunk,
13940        window: &mut Window,
13941        cx: &mut Context<Self>,
13942    ) {
13943        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13944        let snapshot = self.snapshot(window, cx);
13945        let selection = self.selections.newest::<Point>(cx);
13946        self.go_to_hunk_before_or_after_position(
13947            &snapshot,
13948            selection.head(),
13949            Direction::Prev,
13950            window,
13951            cx,
13952        );
13953    }
13954
13955    fn hunk_before_position(
13956        &mut self,
13957        snapshot: &EditorSnapshot,
13958        position: Point,
13959    ) -> Option<MultiBufferRow> {
13960        snapshot
13961            .buffer_snapshot
13962            .diff_hunk_before(position)
13963            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
13964    }
13965
13966    fn go_to_next_change(
13967        &mut self,
13968        _: &GoToNextChange,
13969        window: &mut Window,
13970        cx: &mut Context<Self>,
13971    ) {
13972        if let Some(selections) = self
13973            .change_list
13974            .next_change(1, Direction::Next)
13975            .map(|s| s.to_vec())
13976        {
13977            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13978                let map = s.display_map();
13979                s.select_display_ranges(selections.iter().map(|a| {
13980                    let point = a.to_display_point(&map);
13981                    point..point
13982                }))
13983            })
13984        }
13985    }
13986
13987    fn go_to_previous_change(
13988        &mut self,
13989        _: &GoToPreviousChange,
13990        window: &mut Window,
13991        cx: &mut Context<Self>,
13992    ) {
13993        if let Some(selections) = self
13994            .change_list
13995            .next_change(1, Direction::Prev)
13996            .map(|s| s.to_vec())
13997        {
13998            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13999                let map = s.display_map();
14000                s.select_display_ranges(selections.iter().map(|a| {
14001                    let point = a.to_display_point(&map);
14002                    point..point
14003                }))
14004            })
14005        }
14006    }
14007
14008    fn go_to_line<T: 'static>(
14009        &mut self,
14010        position: Anchor,
14011        highlight_color: Option<Hsla>,
14012        window: &mut Window,
14013        cx: &mut Context<Self>,
14014    ) {
14015        let snapshot = self.snapshot(window, cx).display_snapshot;
14016        let position = position.to_point(&snapshot.buffer_snapshot);
14017        let start = snapshot
14018            .buffer_snapshot
14019            .clip_point(Point::new(position.row, 0), Bias::Left);
14020        let end = start + Point::new(1, 0);
14021        let start = snapshot.buffer_snapshot.anchor_before(start);
14022        let end = snapshot.buffer_snapshot.anchor_before(end);
14023
14024        self.highlight_rows::<T>(
14025            start..end,
14026            highlight_color
14027                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14028            Default::default(),
14029            cx,
14030        );
14031
14032        if self.buffer.read(cx).is_singleton() {
14033            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14034        }
14035    }
14036
14037    pub fn go_to_definition(
14038        &mut self,
14039        _: &GoToDefinition,
14040        window: &mut Window,
14041        cx: &mut Context<Self>,
14042    ) -> Task<Result<Navigated>> {
14043        let definition =
14044            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14045        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14046        cx.spawn_in(window, async move |editor, cx| {
14047            if definition.await? == Navigated::Yes {
14048                return Ok(Navigated::Yes);
14049            }
14050            match fallback_strategy {
14051                GoToDefinitionFallback::None => Ok(Navigated::No),
14052                GoToDefinitionFallback::FindAllReferences => {
14053                    match editor.update_in(cx, |editor, window, cx| {
14054                        editor.find_all_references(&FindAllReferences, window, cx)
14055                    })? {
14056                        Some(references) => references.await,
14057                        None => Ok(Navigated::No),
14058                    }
14059                }
14060            }
14061        })
14062    }
14063
14064    pub fn go_to_declaration(
14065        &mut self,
14066        _: &GoToDeclaration,
14067        window: &mut Window,
14068        cx: &mut Context<Self>,
14069    ) -> Task<Result<Navigated>> {
14070        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14071    }
14072
14073    pub fn go_to_declaration_split(
14074        &mut self,
14075        _: &GoToDeclaration,
14076        window: &mut Window,
14077        cx: &mut Context<Self>,
14078    ) -> Task<Result<Navigated>> {
14079        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14080    }
14081
14082    pub fn go_to_implementation(
14083        &mut self,
14084        _: &GoToImplementation,
14085        window: &mut Window,
14086        cx: &mut Context<Self>,
14087    ) -> Task<Result<Navigated>> {
14088        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14089    }
14090
14091    pub fn go_to_implementation_split(
14092        &mut self,
14093        _: &GoToImplementationSplit,
14094        window: &mut Window,
14095        cx: &mut Context<Self>,
14096    ) -> Task<Result<Navigated>> {
14097        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14098    }
14099
14100    pub fn go_to_type_definition(
14101        &mut self,
14102        _: &GoToTypeDefinition,
14103        window: &mut Window,
14104        cx: &mut Context<Self>,
14105    ) -> Task<Result<Navigated>> {
14106        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14107    }
14108
14109    pub fn go_to_definition_split(
14110        &mut self,
14111        _: &GoToDefinitionSplit,
14112        window: &mut Window,
14113        cx: &mut Context<Self>,
14114    ) -> Task<Result<Navigated>> {
14115        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14116    }
14117
14118    pub fn go_to_type_definition_split(
14119        &mut self,
14120        _: &GoToTypeDefinitionSplit,
14121        window: &mut Window,
14122        cx: &mut Context<Self>,
14123    ) -> Task<Result<Navigated>> {
14124        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14125    }
14126
14127    fn go_to_definition_of_kind(
14128        &mut self,
14129        kind: GotoDefinitionKind,
14130        split: bool,
14131        window: &mut Window,
14132        cx: &mut Context<Self>,
14133    ) -> Task<Result<Navigated>> {
14134        let Some(provider) = self.semantics_provider.clone() else {
14135            return Task::ready(Ok(Navigated::No));
14136        };
14137        let head = self.selections.newest::<usize>(cx).head();
14138        let buffer = self.buffer.read(cx);
14139        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14140            text_anchor
14141        } else {
14142            return Task::ready(Ok(Navigated::No));
14143        };
14144
14145        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14146            return Task::ready(Ok(Navigated::No));
14147        };
14148
14149        cx.spawn_in(window, async move |editor, cx| {
14150            let definitions = definitions.await?;
14151            let navigated = editor
14152                .update_in(cx, |editor, window, cx| {
14153                    editor.navigate_to_hover_links(
14154                        Some(kind),
14155                        definitions
14156                            .into_iter()
14157                            .filter(|location| {
14158                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14159                            })
14160                            .map(HoverLink::Text)
14161                            .collect::<Vec<_>>(),
14162                        split,
14163                        window,
14164                        cx,
14165                    )
14166                })?
14167                .await?;
14168            anyhow::Ok(navigated)
14169        })
14170    }
14171
14172    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14173        let selection = self.selections.newest_anchor();
14174        let head = selection.head();
14175        let tail = selection.tail();
14176
14177        let Some((buffer, start_position)) =
14178            self.buffer.read(cx).text_anchor_for_position(head, cx)
14179        else {
14180            return;
14181        };
14182
14183        let end_position = if head != tail {
14184            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14185                return;
14186            };
14187            Some(pos)
14188        } else {
14189            None
14190        };
14191
14192        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14193            let url = if let Some(end_pos) = end_position {
14194                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14195            } else {
14196                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14197            };
14198
14199            if let Some(url) = url {
14200                editor.update(cx, |_, cx| {
14201                    cx.open_url(&url);
14202                })
14203            } else {
14204                Ok(())
14205            }
14206        });
14207
14208        url_finder.detach();
14209    }
14210
14211    pub fn open_selected_filename(
14212        &mut self,
14213        _: &OpenSelectedFilename,
14214        window: &mut Window,
14215        cx: &mut Context<Self>,
14216    ) {
14217        let Some(workspace) = self.workspace() else {
14218            return;
14219        };
14220
14221        let position = self.selections.newest_anchor().head();
14222
14223        let Some((buffer, buffer_position)) =
14224            self.buffer.read(cx).text_anchor_for_position(position, cx)
14225        else {
14226            return;
14227        };
14228
14229        let project = self.project.clone();
14230
14231        cx.spawn_in(window, async move |_, cx| {
14232            let result = find_file(&buffer, project, buffer_position, cx).await;
14233
14234            if let Some((_, path)) = result {
14235                workspace
14236                    .update_in(cx, |workspace, window, cx| {
14237                        workspace.open_resolved_path(path, window, cx)
14238                    })?
14239                    .await?;
14240            }
14241            anyhow::Ok(())
14242        })
14243        .detach();
14244    }
14245
14246    pub(crate) fn navigate_to_hover_links(
14247        &mut self,
14248        kind: Option<GotoDefinitionKind>,
14249        mut definitions: Vec<HoverLink>,
14250        split: bool,
14251        window: &mut Window,
14252        cx: &mut Context<Editor>,
14253    ) -> Task<Result<Navigated>> {
14254        // If there is one definition, just open it directly
14255        if definitions.len() == 1 {
14256            let definition = definitions.pop().unwrap();
14257
14258            enum TargetTaskResult {
14259                Location(Option<Location>),
14260                AlreadyNavigated,
14261            }
14262
14263            let target_task = match definition {
14264                HoverLink::Text(link) => {
14265                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14266                }
14267                HoverLink::InlayHint(lsp_location, server_id) => {
14268                    let computation =
14269                        self.compute_target_location(lsp_location, server_id, window, cx);
14270                    cx.background_spawn(async move {
14271                        let location = computation.await?;
14272                        Ok(TargetTaskResult::Location(location))
14273                    })
14274                }
14275                HoverLink::Url(url) => {
14276                    cx.open_url(&url);
14277                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14278                }
14279                HoverLink::File(path) => {
14280                    if let Some(workspace) = self.workspace() {
14281                        cx.spawn_in(window, async move |_, cx| {
14282                            workspace
14283                                .update_in(cx, |workspace, window, cx| {
14284                                    workspace.open_resolved_path(path, window, cx)
14285                                })?
14286                                .await
14287                                .map(|_| TargetTaskResult::AlreadyNavigated)
14288                        })
14289                    } else {
14290                        Task::ready(Ok(TargetTaskResult::Location(None)))
14291                    }
14292                }
14293            };
14294            cx.spawn_in(window, async move |editor, cx| {
14295                let target = match target_task.await.context("target resolution task")? {
14296                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14297                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14298                    TargetTaskResult::Location(Some(target)) => target,
14299                };
14300
14301                editor.update_in(cx, |editor, window, cx| {
14302                    let Some(workspace) = editor.workspace() else {
14303                        return Navigated::No;
14304                    };
14305                    let pane = workspace.read(cx).active_pane().clone();
14306
14307                    let range = target.range.to_point(target.buffer.read(cx));
14308                    let range = editor.range_for_match(&range);
14309                    let range = collapse_multiline_range(range);
14310
14311                    if !split
14312                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14313                    {
14314                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14315                    } else {
14316                        window.defer(cx, move |window, cx| {
14317                            let target_editor: Entity<Self> =
14318                                workspace.update(cx, |workspace, cx| {
14319                                    let pane = if split {
14320                                        workspace.adjacent_pane(window, cx)
14321                                    } else {
14322                                        workspace.active_pane().clone()
14323                                    };
14324
14325                                    workspace.open_project_item(
14326                                        pane,
14327                                        target.buffer.clone(),
14328                                        true,
14329                                        true,
14330                                        window,
14331                                        cx,
14332                                    )
14333                                });
14334                            target_editor.update(cx, |target_editor, cx| {
14335                                // When selecting a definition in a different buffer, disable the nav history
14336                                // to avoid creating a history entry at the previous cursor location.
14337                                pane.update(cx, |pane, _| pane.disable_history());
14338                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14339                                pane.update(cx, |pane, _| pane.enable_history());
14340                            });
14341                        });
14342                    }
14343                    Navigated::Yes
14344                })
14345            })
14346        } else if !definitions.is_empty() {
14347            cx.spawn_in(window, async move |editor, cx| {
14348                let (title, location_tasks, workspace) = editor
14349                    .update_in(cx, |editor, window, cx| {
14350                        let tab_kind = match kind {
14351                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14352                            _ => "Definitions",
14353                        };
14354                        let title = definitions
14355                            .iter()
14356                            .find_map(|definition| match definition {
14357                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
14358                                    let buffer = origin.buffer.read(cx);
14359                                    format!(
14360                                        "{} for {}",
14361                                        tab_kind,
14362                                        buffer
14363                                            .text_for_range(origin.range.clone())
14364                                            .collect::<String>()
14365                                    )
14366                                }),
14367                                HoverLink::InlayHint(_, _) => None,
14368                                HoverLink::Url(_) => None,
14369                                HoverLink::File(_) => None,
14370                            })
14371                            .unwrap_or(tab_kind.to_string());
14372                        let location_tasks = definitions
14373                            .into_iter()
14374                            .map(|definition| match definition {
14375                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
14376                                HoverLink::InlayHint(lsp_location, server_id) => editor
14377                                    .compute_target_location(lsp_location, server_id, window, cx),
14378                                HoverLink::Url(_) => Task::ready(Ok(None)),
14379                                HoverLink::File(_) => Task::ready(Ok(None)),
14380                            })
14381                            .collect::<Vec<_>>();
14382                        (title, location_tasks, editor.workspace().clone())
14383                    })
14384                    .context("location tasks preparation")?;
14385
14386                let locations = future::join_all(location_tasks)
14387                    .await
14388                    .into_iter()
14389                    .filter_map(|location| location.transpose())
14390                    .collect::<Result<_>>()
14391                    .context("location tasks")?;
14392
14393                let Some(workspace) = workspace else {
14394                    return Ok(Navigated::No);
14395                };
14396                let opened = workspace
14397                    .update_in(cx, |workspace, window, cx| {
14398                        Self::open_locations_in_multibuffer(
14399                            workspace,
14400                            locations,
14401                            title,
14402                            split,
14403                            MultibufferSelectionMode::First,
14404                            window,
14405                            cx,
14406                        )
14407                    })
14408                    .ok();
14409
14410                anyhow::Ok(Navigated::from_bool(opened.is_some()))
14411            })
14412        } else {
14413            Task::ready(Ok(Navigated::No))
14414        }
14415    }
14416
14417    fn compute_target_location(
14418        &self,
14419        lsp_location: lsp::Location,
14420        server_id: LanguageServerId,
14421        window: &mut Window,
14422        cx: &mut Context<Self>,
14423    ) -> Task<anyhow::Result<Option<Location>>> {
14424        let Some(project) = self.project.clone() else {
14425            return Task::ready(Ok(None));
14426        };
14427
14428        cx.spawn_in(window, async move |editor, cx| {
14429            let location_task = editor.update(cx, |_, cx| {
14430                project.update(cx, |project, cx| {
14431                    let language_server_name = project
14432                        .language_server_statuses(cx)
14433                        .find(|(id, _)| server_id == *id)
14434                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
14435                    language_server_name.map(|language_server_name| {
14436                        project.open_local_buffer_via_lsp(
14437                            lsp_location.uri.clone(),
14438                            server_id,
14439                            language_server_name,
14440                            cx,
14441                        )
14442                    })
14443                })
14444            })?;
14445            let location = match location_task {
14446                Some(task) => Some({
14447                    let target_buffer_handle = task.await.context("open local buffer")?;
14448                    let range = target_buffer_handle.update(cx, |target_buffer, _| {
14449                        let target_start = target_buffer
14450                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
14451                        let target_end = target_buffer
14452                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
14453                        target_buffer.anchor_after(target_start)
14454                            ..target_buffer.anchor_before(target_end)
14455                    })?;
14456                    Location {
14457                        buffer: target_buffer_handle,
14458                        range,
14459                    }
14460                }),
14461                None => None,
14462            };
14463            Ok(location)
14464        })
14465    }
14466
14467    pub fn find_all_references(
14468        &mut self,
14469        _: &FindAllReferences,
14470        window: &mut Window,
14471        cx: &mut Context<Self>,
14472    ) -> Option<Task<Result<Navigated>>> {
14473        let selection = self.selections.newest::<usize>(cx);
14474        let multi_buffer = self.buffer.read(cx);
14475        let head = selection.head();
14476
14477        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
14478        let head_anchor = multi_buffer_snapshot.anchor_at(
14479            head,
14480            if head < selection.tail() {
14481                Bias::Right
14482            } else {
14483                Bias::Left
14484            },
14485        );
14486
14487        match self
14488            .find_all_references_task_sources
14489            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14490        {
14491            Ok(_) => {
14492                log::info!(
14493                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
14494                );
14495                return None;
14496            }
14497            Err(i) => {
14498                self.find_all_references_task_sources.insert(i, head_anchor);
14499            }
14500        }
14501
14502        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
14503        let workspace = self.workspace()?;
14504        let project = workspace.read(cx).project().clone();
14505        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
14506        Some(cx.spawn_in(window, async move |editor, cx| {
14507            let _cleanup = cx.on_drop(&editor, move |editor, _| {
14508                if let Ok(i) = editor
14509                    .find_all_references_task_sources
14510                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14511                {
14512                    editor.find_all_references_task_sources.remove(i);
14513                }
14514            });
14515
14516            let locations = references.await?;
14517            if locations.is_empty() {
14518                return anyhow::Ok(Navigated::No);
14519            }
14520
14521            workspace.update_in(cx, |workspace, window, cx| {
14522                let title = locations
14523                    .first()
14524                    .as_ref()
14525                    .map(|location| {
14526                        let buffer = location.buffer.read(cx);
14527                        format!(
14528                            "References to `{}`",
14529                            buffer
14530                                .text_for_range(location.range.clone())
14531                                .collect::<String>()
14532                        )
14533                    })
14534                    .unwrap();
14535                Self::open_locations_in_multibuffer(
14536                    workspace,
14537                    locations,
14538                    title,
14539                    false,
14540                    MultibufferSelectionMode::First,
14541                    window,
14542                    cx,
14543                );
14544                Navigated::Yes
14545            })
14546        }))
14547    }
14548
14549    /// Opens a multibuffer with the given project locations in it
14550    pub fn open_locations_in_multibuffer(
14551        workspace: &mut Workspace,
14552        mut locations: Vec<Location>,
14553        title: String,
14554        split: bool,
14555        multibuffer_selection_mode: MultibufferSelectionMode,
14556        window: &mut Window,
14557        cx: &mut Context<Workspace>,
14558    ) {
14559        // If there are multiple definitions, open them in a multibuffer
14560        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
14561        let mut locations = locations.into_iter().peekable();
14562        let mut ranges: Vec<Range<Anchor>> = Vec::new();
14563        let capability = workspace.project().read(cx).capability();
14564
14565        let excerpt_buffer = cx.new(|cx| {
14566            let mut multibuffer = MultiBuffer::new(capability);
14567            while let Some(location) = locations.next() {
14568                let buffer = location.buffer.read(cx);
14569                let mut ranges_for_buffer = Vec::new();
14570                let range = location.range.to_point(buffer);
14571                ranges_for_buffer.push(range.clone());
14572
14573                while let Some(next_location) = locations.peek() {
14574                    if next_location.buffer == location.buffer {
14575                        ranges_for_buffer.push(next_location.range.to_point(buffer));
14576                        locations.next();
14577                    } else {
14578                        break;
14579                    }
14580                }
14581
14582                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
14583                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
14584                    PathKey::for_buffer(&location.buffer, cx),
14585                    location.buffer.clone(),
14586                    ranges_for_buffer,
14587                    DEFAULT_MULTIBUFFER_CONTEXT,
14588                    cx,
14589                );
14590                ranges.extend(new_ranges)
14591            }
14592
14593            multibuffer.with_title(title)
14594        });
14595
14596        let editor = cx.new(|cx| {
14597            Editor::for_multibuffer(
14598                excerpt_buffer,
14599                Some(workspace.project().clone()),
14600                window,
14601                cx,
14602            )
14603        });
14604        editor.update(cx, |editor, cx| {
14605            match multibuffer_selection_mode {
14606                MultibufferSelectionMode::First => {
14607                    if let Some(first_range) = ranges.first() {
14608                        editor.change_selections(None, window, cx, |selections| {
14609                            selections.clear_disjoint();
14610                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
14611                        });
14612                    }
14613                    editor.highlight_background::<Self>(
14614                        &ranges,
14615                        |theme| theme.editor_highlighted_line_background,
14616                        cx,
14617                    );
14618                }
14619                MultibufferSelectionMode::All => {
14620                    editor.change_selections(None, window, cx, |selections| {
14621                        selections.clear_disjoint();
14622                        selections.select_anchor_ranges(ranges);
14623                    });
14624                }
14625            }
14626            editor.register_buffers_with_language_servers(cx);
14627        });
14628
14629        let item = Box::new(editor);
14630        let item_id = item.item_id();
14631
14632        if split {
14633            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
14634        } else {
14635            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
14636                let (preview_item_id, preview_item_idx) =
14637                    workspace.active_pane().update(cx, |pane, _| {
14638                        (pane.preview_item_id(), pane.preview_item_idx())
14639                    });
14640
14641                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
14642
14643                if let Some(preview_item_id) = preview_item_id {
14644                    workspace.active_pane().update(cx, |pane, cx| {
14645                        pane.remove_item(preview_item_id, false, false, window, cx);
14646                    });
14647                }
14648            } else {
14649                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
14650            }
14651        }
14652        workspace.active_pane().update(cx, |pane, cx| {
14653            pane.set_preview_item_id(Some(item_id), cx);
14654        });
14655    }
14656
14657    pub fn rename(
14658        &mut self,
14659        _: &Rename,
14660        window: &mut Window,
14661        cx: &mut Context<Self>,
14662    ) -> Option<Task<Result<()>>> {
14663        use language::ToOffset as _;
14664
14665        let provider = self.semantics_provider.clone()?;
14666        let selection = self.selections.newest_anchor().clone();
14667        let (cursor_buffer, cursor_buffer_position) = self
14668            .buffer
14669            .read(cx)
14670            .text_anchor_for_position(selection.head(), cx)?;
14671        let (tail_buffer, cursor_buffer_position_end) = self
14672            .buffer
14673            .read(cx)
14674            .text_anchor_for_position(selection.tail(), cx)?;
14675        if tail_buffer != cursor_buffer {
14676            return None;
14677        }
14678
14679        let snapshot = cursor_buffer.read(cx).snapshot();
14680        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
14681        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
14682        let prepare_rename = provider
14683            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
14684            .unwrap_or_else(|| Task::ready(Ok(None)));
14685        drop(snapshot);
14686
14687        Some(cx.spawn_in(window, async move |this, cx| {
14688            let rename_range = if let Some(range) = prepare_rename.await? {
14689                Some(range)
14690            } else {
14691                this.update(cx, |this, cx| {
14692                    let buffer = this.buffer.read(cx).snapshot(cx);
14693                    let mut buffer_highlights = this
14694                        .document_highlights_for_position(selection.head(), &buffer)
14695                        .filter(|highlight| {
14696                            highlight.start.excerpt_id == selection.head().excerpt_id
14697                                && highlight.end.excerpt_id == selection.head().excerpt_id
14698                        });
14699                    buffer_highlights
14700                        .next()
14701                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
14702                })?
14703            };
14704            if let Some(rename_range) = rename_range {
14705                this.update_in(cx, |this, window, cx| {
14706                    let snapshot = cursor_buffer.read(cx).snapshot();
14707                    let rename_buffer_range = rename_range.to_offset(&snapshot);
14708                    let cursor_offset_in_rename_range =
14709                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
14710                    let cursor_offset_in_rename_range_end =
14711                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
14712
14713                    this.take_rename(false, window, cx);
14714                    let buffer = this.buffer.read(cx).read(cx);
14715                    let cursor_offset = selection.head().to_offset(&buffer);
14716                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
14717                    let rename_end = rename_start + rename_buffer_range.len();
14718                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
14719                    let mut old_highlight_id = None;
14720                    let old_name: Arc<str> = buffer
14721                        .chunks(rename_start..rename_end, true)
14722                        .map(|chunk| {
14723                            if old_highlight_id.is_none() {
14724                                old_highlight_id = chunk.syntax_highlight_id;
14725                            }
14726                            chunk.text
14727                        })
14728                        .collect::<String>()
14729                        .into();
14730
14731                    drop(buffer);
14732
14733                    // Position the selection in the rename editor so that it matches the current selection.
14734                    this.show_local_selections = false;
14735                    let rename_editor = cx.new(|cx| {
14736                        let mut editor = Editor::single_line(window, cx);
14737                        editor.buffer.update(cx, |buffer, cx| {
14738                            buffer.edit([(0..0, old_name.clone())], None, cx)
14739                        });
14740                        let rename_selection_range = match cursor_offset_in_rename_range
14741                            .cmp(&cursor_offset_in_rename_range_end)
14742                        {
14743                            Ordering::Equal => {
14744                                editor.select_all(&SelectAll, window, cx);
14745                                return editor;
14746                            }
14747                            Ordering::Less => {
14748                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
14749                            }
14750                            Ordering::Greater => {
14751                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
14752                            }
14753                        };
14754                        if rename_selection_range.end > old_name.len() {
14755                            editor.select_all(&SelectAll, window, cx);
14756                        } else {
14757                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14758                                s.select_ranges([rename_selection_range]);
14759                            });
14760                        }
14761                        editor
14762                    });
14763                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
14764                        if e == &EditorEvent::Focused {
14765                            cx.emit(EditorEvent::FocusedIn)
14766                        }
14767                    })
14768                    .detach();
14769
14770                    let write_highlights =
14771                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
14772                    let read_highlights =
14773                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
14774                    let ranges = write_highlights
14775                        .iter()
14776                        .flat_map(|(_, ranges)| ranges.iter())
14777                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
14778                        .cloned()
14779                        .collect();
14780
14781                    this.highlight_text::<Rename>(
14782                        ranges,
14783                        HighlightStyle {
14784                            fade_out: Some(0.6),
14785                            ..Default::default()
14786                        },
14787                        cx,
14788                    );
14789                    let rename_focus_handle = rename_editor.focus_handle(cx);
14790                    window.focus(&rename_focus_handle);
14791                    let block_id = this.insert_blocks(
14792                        [BlockProperties {
14793                            style: BlockStyle::Flex,
14794                            placement: BlockPlacement::Below(range.start),
14795                            height: Some(1),
14796                            render: Arc::new({
14797                                let rename_editor = rename_editor.clone();
14798                                move |cx: &mut BlockContext| {
14799                                    let mut text_style = cx.editor_style.text.clone();
14800                                    if let Some(highlight_style) = old_highlight_id
14801                                        .and_then(|h| h.style(&cx.editor_style.syntax))
14802                                    {
14803                                        text_style = text_style.highlight(highlight_style);
14804                                    }
14805                                    div()
14806                                        .block_mouse_down()
14807                                        .pl(cx.anchor_x)
14808                                        .child(EditorElement::new(
14809                                            &rename_editor,
14810                                            EditorStyle {
14811                                                background: cx.theme().system().transparent,
14812                                                local_player: cx.editor_style.local_player,
14813                                                text: text_style,
14814                                                scrollbar_width: cx.editor_style.scrollbar_width,
14815                                                syntax: cx.editor_style.syntax.clone(),
14816                                                status: cx.editor_style.status.clone(),
14817                                                inlay_hints_style: HighlightStyle {
14818                                                    font_weight: Some(FontWeight::BOLD),
14819                                                    ..make_inlay_hints_style(cx.app)
14820                                                },
14821                                                inline_completion_styles: make_suggestion_styles(
14822                                                    cx.app,
14823                                                ),
14824                                                ..EditorStyle::default()
14825                                            },
14826                                        ))
14827                                        .into_any_element()
14828                                }
14829                            }),
14830                            priority: 0,
14831                            render_in_minimap: true,
14832                        }],
14833                        Some(Autoscroll::fit()),
14834                        cx,
14835                    )[0];
14836                    this.pending_rename = Some(RenameState {
14837                        range,
14838                        old_name,
14839                        editor: rename_editor,
14840                        block_id,
14841                    });
14842                })?;
14843            }
14844
14845            Ok(())
14846        }))
14847    }
14848
14849    pub fn confirm_rename(
14850        &mut self,
14851        _: &ConfirmRename,
14852        window: &mut Window,
14853        cx: &mut Context<Self>,
14854    ) -> Option<Task<Result<()>>> {
14855        let rename = self.take_rename(false, window, cx)?;
14856        let workspace = self.workspace()?.downgrade();
14857        let (buffer, start) = self
14858            .buffer
14859            .read(cx)
14860            .text_anchor_for_position(rename.range.start, cx)?;
14861        let (end_buffer, _) = self
14862            .buffer
14863            .read(cx)
14864            .text_anchor_for_position(rename.range.end, cx)?;
14865        if buffer != end_buffer {
14866            return None;
14867        }
14868
14869        let old_name = rename.old_name;
14870        let new_name = rename.editor.read(cx).text(cx);
14871
14872        let rename = self.semantics_provider.as_ref()?.perform_rename(
14873            &buffer,
14874            start,
14875            new_name.clone(),
14876            cx,
14877        )?;
14878
14879        Some(cx.spawn_in(window, async move |editor, cx| {
14880            let project_transaction = rename.await?;
14881            Self::open_project_transaction(
14882                &editor,
14883                workspace,
14884                project_transaction,
14885                format!("Rename: {}{}", old_name, new_name),
14886                cx,
14887            )
14888            .await?;
14889
14890            editor.update(cx, |editor, cx| {
14891                editor.refresh_document_highlights(cx);
14892            })?;
14893            Ok(())
14894        }))
14895    }
14896
14897    fn take_rename(
14898        &mut self,
14899        moving_cursor: bool,
14900        window: &mut Window,
14901        cx: &mut Context<Self>,
14902    ) -> Option<RenameState> {
14903        let rename = self.pending_rename.take()?;
14904        if rename.editor.focus_handle(cx).is_focused(window) {
14905            window.focus(&self.focus_handle);
14906        }
14907
14908        self.remove_blocks(
14909            [rename.block_id].into_iter().collect(),
14910            Some(Autoscroll::fit()),
14911            cx,
14912        );
14913        self.clear_highlights::<Rename>(cx);
14914        self.show_local_selections = true;
14915
14916        if moving_cursor {
14917            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
14918                editor.selections.newest::<usize>(cx).head()
14919            });
14920
14921            // Update the selection to match the position of the selection inside
14922            // the rename editor.
14923            let snapshot = self.buffer.read(cx).read(cx);
14924            let rename_range = rename.range.to_offset(&snapshot);
14925            let cursor_in_editor = snapshot
14926                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
14927                .min(rename_range.end);
14928            drop(snapshot);
14929
14930            self.change_selections(None, window, cx, |s| {
14931                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
14932            });
14933        } else {
14934            self.refresh_document_highlights(cx);
14935        }
14936
14937        Some(rename)
14938    }
14939
14940    pub fn pending_rename(&self) -> Option<&RenameState> {
14941        self.pending_rename.as_ref()
14942    }
14943
14944    fn format(
14945        &mut self,
14946        _: &Format,
14947        window: &mut Window,
14948        cx: &mut Context<Self>,
14949    ) -> Option<Task<Result<()>>> {
14950        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
14951
14952        let project = match &self.project {
14953            Some(project) => project.clone(),
14954            None => return None,
14955        };
14956
14957        Some(self.perform_format(
14958            project,
14959            FormatTrigger::Manual,
14960            FormatTarget::Buffers,
14961            window,
14962            cx,
14963        ))
14964    }
14965
14966    fn format_selections(
14967        &mut self,
14968        _: &FormatSelections,
14969        window: &mut Window,
14970        cx: &mut Context<Self>,
14971    ) -> Option<Task<Result<()>>> {
14972        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
14973
14974        let project = match &self.project {
14975            Some(project) => project.clone(),
14976            None => return None,
14977        };
14978
14979        let ranges = self
14980            .selections
14981            .all_adjusted(cx)
14982            .into_iter()
14983            .map(|selection| selection.range())
14984            .collect_vec();
14985
14986        Some(self.perform_format(
14987            project,
14988            FormatTrigger::Manual,
14989            FormatTarget::Ranges(ranges),
14990            window,
14991            cx,
14992        ))
14993    }
14994
14995    fn perform_format(
14996        &mut self,
14997        project: Entity<Project>,
14998        trigger: FormatTrigger,
14999        target: FormatTarget,
15000        window: &mut Window,
15001        cx: &mut Context<Self>,
15002    ) -> Task<Result<()>> {
15003        let buffer = self.buffer.clone();
15004        let (buffers, target) = match target {
15005            FormatTarget::Buffers => {
15006                let mut buffers = buffer.read(cx).all_buffers();
15007                if trigger == FormatTrigger::Save {
15008                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15009                }
15010                (buffers, LspFormatTarget::Buffers)
15011            }
15012            FormatTarget::Ranges(selection_ranges) => {
15013                let multi_buffer = buffer.read(cx);
15014                let snapshot = multi_buffer.read(cx);
15015                let mut buffers = HashSet::default();
15016                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15017                    BTreeMap::new();
15018                for selection_range in selection_ranges {
15019                    for (buffer, buffer_range, _) in
15020                        snapshot.range_to_buffer_ranges(selection_range)
15021                    {
15022                        let buffer_id = buffer.remote_id();
15023                        let start = buffer.anchor_before(buffer_range.start);
15024                        let end = buffer.anchor_after(buffer_range.end);
15025                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15026                        buffer_id_to_ranges
15027                            .entry(buffer_id)
15028                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15029                            .or_insert_with(|| vec![start..end]);
15030                    }
15031                }
15032                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15033            }
15034        };
15035
15036        let transaction_id_prev = buffer.read_with(cx, |b, cx| b.last_transaction_id(cx));
15037        let selections_prev = transaction_id_prev
15038            .and_then(|transaction_id_prev| {
15039                // default to selections as they were after the last edit, if we have them,
15040                // instead of how they are now.
15041                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15042                // will take you back to where you made the last edit, instead of staying where you scrolled
15043                self.selection_history
15044                    .transaction(transaction_id_prev)
15045                    .map(|t| t.0.clone())
15046            })
15047            .unwrap_or_else(|| {
15048                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15049                self.selections.disjoint_anchors()
15050            });
15051
15052        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15053        let format = project.update(cx, |project, cx| {
15054            project.format(buffers, target, true, trigger, cx)
15055        });
15056
15057        cx.spawn_in(window, async move |editor, cx| {
15058            let transaction = futures::select_biased! {
15059                transaction = format.log_err().fuse() => transaction,
15060                () = timeout => {
15061                    log::warn!("timed out waiting for formatting");
15062                    None
15063                }
15064            };
15065
15066            buffer
15067                .update(cx, |buffer, cx| {
15068                    if let Some(transaction) = transaction {
15069                        if !buffer.is_singleton() {
15070                            buffer.push_transaction(&transaction.0, cx);
15071                        }
15072                    }
15073                    cx.notify();
15074                })
15075                .ok();
15076
15077            if let Some(transaction_id_now) =
15078                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15079            {
15080                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15081                if has_new_transaction {
15082                    _ = editor.update(cx, |editor, _| {
15083                        editor
15084                            .selection_history
15085                            .insert_transaction(transaction_id_now, selections_prev);
15086                    });
15087                }
15088            }
15089
15090            Ok(())
15091        })
15092    }
15093
15094    fn organize_imports(
15095        &mut self,
15096        _: &OrganizeImports,
15097        window: &mut Window,
15098        cx: &mut Context<Self>,
15099    ) -> Option<Task<Result<()>>> {
15100        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15101        let project = match &self.project {
15102            Some(project) => project.clone(),
15103            None => return None,
15104        };
15105        Some(self.perform_code_action_kind(
15106            project,
15107            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15108            window,
15109            cx,
15110        ))
15111    }
15112
15113    fn perform_code_action_kind(
15114        &mut self,
15115        project: Entity<Project>,
15116        kind: CodeActionKind,
15117        window: &mut Window,
15118        cx: &mut Context<Self>,
15119    ) -> Task<Result<()>> {
15120        let buffer = self.buffer.clone();
15121        let buffers = buffer.read(cx).all_buffers();
15122        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15123        let apply_action = project.update(cx, |project, cx| {
15124            project.apply_code_action_kind(buffers, kind, true, cx)
15125        });
15126        cx.spawn_in(window, async move |_, cx| {
15127            let transaction = futures::select_biased! {
15128                () = timeout => {
15129                    log::warn!("timed out waiting for executing code action");
15130                    None
15131                }
15132                transaction = apply_action.log_err().fuse() => transaction,
15133            };
15134            buffer
15135                .update(cx, |buffer, cx| {
15136                    // check if we need this
15137                    if let Some(transaction) = transaction {
15138                        if !buffer.is_singleton() {
15139                            buffer.push_transaction(&transaction.0, cx);
15140                        }
15141                    }
15142                    cx.notify();
15143                })
15144                .ok();
15145            Ok(())
15146        })
15147    }
15148
15149    fn restart_language_server(
15150        &mut self,
15151        _: &RestartLanguageServer,
15152        _: &mut Window,
15153        cx: &mut Context<Self>,
15154    ) {
15155        if let Some(project) = self.project.clone() {
15156            self.buffer.update(cx, |multi_buffer, cx| {
15157                project.update(cx, |project, cx| {
15158                    project.restart_language_servers_for_buffers(
15159                        multi_buffer.all_buffers().into_iter().collect(),
15160                        cx,
15161                    );
15162                });
15163            })
15164        }
15165    }
15166
15167    fn stop_language_server(
15168        &mut self,
15169        _: &StopLanguageServer,
15170        _: &mut Window,
15171        cx: &mut Context<Self>,
15172    ) {
15173        if let Some(project) = self.project.clone() {
15174            self.buffer.update(cx, |multi_buffer, cx| {
15175                project.update(cx, |project, cx| {
15176                    project.stop_language_servers_for_buffers(
15177                        multi_buffer.all_buffers().into_iter().collect(),
15178                        cx,
15179                    );
15180                    cx.emit(project::Event::RefreshInlayHints);
15181                });
15182            });
15183        }
15184    }
15185
15186    fn cancel_language_server_work(
15187        workspace: &mut Workspace,
15188        _: &actions::CancelLanguageServerWork,
15189        _: &mut Window,
15190        cx: &mut Context<Workspace>,
15191    ) {
15192        let project = workspace.project();
15193        let buffers = workspace
15194            .active_item(cx)
15195            .and_then(|item| item.act_as::<Editor>(cx))
15196            .map_or(HashSet::default(), |editor| {
15197                editor.read(cx).buffer.read(cx).all_buffers()
15198            });
15199        project.update(cx, |project, cx| {
15200            project.cancel_language_server_work_for_buffers(buffers, cx);
15201        });
15202    }
15203
15204    fn show_character_palette(
15205        &mut self,
15206        _: &ShowCharacterPalette,
15207        window: &mut Window,
15208        _: &mut Context<Self>,
15209    ) {
15210        window.show_character_palette();
15211    }
15212
15213    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15214        if self.mode.is_minimap() {
15215            return;
15216        }
15217
15218        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15219            let buffer = self.buffer.read(cx).snapshot(cx);
15220            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15221            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15222            let is_valid = buffer
15223                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15224                .any(|entry| {
15225                    entry.diagnostic.is_primary
15226                        && !entry.range.is_empty()
15227                        && entry.range.start == primary_range_start
15228                        && entry.diagnostic.message == active_diagnostics.active_message
15229                });
15230
15231            if !is_valid {
15232                self.dismiss_diagnostics(cx);
15233            }
15234        }
15235    }
15236
15237    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15238        match &self.active_diagnostics {
15239            ActiveDiagnostic::Group(group) => Some(group),
15240            _ => None,
15241        }
15242    }
15243
15244    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15245        self.dismiss_diagnostics(cx);
15246        self.active_diagnostics = ActiveDiagnostic::All;
15247    }
15248
15249    fn activate_diagnostics(
15250        &mut self,
15251        buffer_id: BufferId,
15252        diagnostic: DiagnosticEntry<usize>,
15253        window: &mut Window,
15254        cx: &mut Context<Self>,
15255    ) {
15256        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15257            return;
15258        }
15259        self.dismiss_diagnostics(cx);
15260        let snapshot = self.snapshot(window, cx);
15261        let buffer = self.buffer.read(cx).snapshot(cx);
15262        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15263            return;
15264        };
15265
15266        let diagnostic_group = buffer
15267            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15268            .collect::<Vec<_>>();
15269
15270        let blocks =
15271            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15272
15273        let blocks = self.display_map.update(cx, |display_map, cx| {
15274            display_map.insert_blocks(blocks, cx).into_iter().collect()
15275        });
15276        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15277            active_range: buffer.anchor_before(diagnostic.range.start)
15278                ..buffer.anchor_after(diagnostic.range.end),
15279            active_message: diagnostic.diagnostic.message.clone(),
15280            group_id: diagnostic.diagnostic.group_id,
15281            blocks,
15282        });
15283        cx.notify();
15284    }
15285
15286    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15287        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15288            return;
15289        };
15290
15291        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15292        if let ActiveDiagnostic::Group(group) = prev {
15293            self.display_map.update(cx, |display_map, cx| {
15294                display_map.remove_blocks(group.blocks, cx);
15295            });
15296            cx.notify();
15297        }
15298    }
15299
15300    /// Disable inline diagnostics rendering for this editor.
15301    pub fn disable_inline_diagnostics(&mut self) {
15302        self.inline_diagnostics_enabled = false;
15303        self.inline_diagnostics_update = Task::ready(());
15304        self.inline_diagnostics.clear();
15305    }
15306
15307    pub fn diagnostics_enabled(&self) -> bool {
15308        self.mode.is_full()
15309    }
15310
15311    pub fn inline_diagnostics_enabled(&self) -> bool {
15312        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15313    }
15314
15315    pub fn show_inline_diagnostics(&self) -> bool {
15316        self.show_inline_diagnostics
15317    }
15318
15319    pub fn toggle_inline_diagnostics(
15320        &mut self,
15321        _: &ToggleInlineDiagnostics,
15322        window: &mut Window,
15323        cx: &mut Context<Editor>,
15324    ) {
15325        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15326        self.refresh_inline_diagnostics(false, window, cx);
15327    }
15328
15329    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15330        self.diagnostics_max_severity = severity;
15331        self.display_map.update(cx, |display_map, _| {
15332            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15333        });
15334    }
15335
15336    pub fn toggle_diagnostics(
15337        &mut self,
15338        _: &ToggleDiagnostics,
15339        window: &mut Window,
15340        cx: &mut Context<Editor>,
15341    ) {
15342        if !self.diagnostics_enabled() {
15343            return;
15344        }
15345
15346        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15347            EditorSettings::get_global(cx)
15348                .diagnostics_max_severity
15349                .filter(|severity| severity != &DiagnosticSeverity::Off)
15350                .unwrap_or(DiagnosticSeverity::Hint)
15351        } else {
15352            DiagnosticSeverity::Off
15353        };
15354        self.set_max_diagnostics_severity(new_severity, cx);
15355        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15356            self.active_diagnostics = ActiveDiagnostic::None;
15357            self.inline_diagnostics_update = Task::ready(());
15358            self.inline_diagnostics.clear();
15359        } else {
15360            self.refresh_inline_diagnostics(false, window, cx);
15361        }
15362
15363        cx.notify();
15364    }
15365
15366    pub fn toggle_minimap(
15367        &mut self,
15368        _: &ToggleMinimap,
15369        window: &mut Window,
15370        cx: &mut Context<Editor>,
15371    ) {
15372        if self.supports_minimap(cx) {
15373            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
15374        }
15375    }
15376
15377    fn refresh_inline_diagnostics(
15378        &mut self,
15379        debounce: bool,
15380        window: &mut Window,
15381        cx: &mut Context<Self>,
15382    ) {
15383        let max_severity = ProjectSettings::get_global(cx)
15384            .diagnostics
15385            .inline
15386            .max_severity
15387            .unwrap_or(self.diagnostics_max_severity);
15388
15389        if self.mode.is_minimap()
15390            || !self.inline_diagnostics_enabled()
15391            || !self.show_inline_diagnostics
15392            || max_severity == DiagnosticSeverity::Off
15393        {
15394            self.inline_diagnostics_update = Task::ready(());
15395            self.inline_diagnostics.clear();
15396            return;
15397        }
15398
15399        let debounce_ms = ProjectSettings::get_global(cx)
15400            .diagnostics
15401            .inline
15402            .update_debounce_ms;
15403        let debounce = if debounce && debounce_ms > 0 {
15404            Some(Duration::from_millis(debounce_ms))
15405        } else {
15406            None
15407        };
15408        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
15409            let editor = editor.upgrade().unwrap();
15410
15411            if let Some(debounce) = debounce {
15412                cx.background_executor().timer(debounce).await;
15413            }
15414            let Some(snapshot) = editor
15415                .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
15416                .ok()
15417            else {
15418                return;
15419            };
15420
15421            let new_inline_diagnostics = cx
15422                .background_spawn(async move {
15423                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
15424                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
15425                        let message = diagnostic_entry
15426                            .diagnostic
15427                            .message
15428                            .split_once('\n')
15429                            .map(|(line, _)| line)
15430                            .map(SharedString::new)
15431                            .unwrap_or_else(|| {
15432                                SharedString::from(diagnostic_entry.diagnostic.message)
15433                            });
15434                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
15435                        let (Ok(i) | Err(i)) = inline_diagnostics
15436                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
15437                        inline_diagnostics.insert(
15438                            i,
15439                            (
15440                                start_anchor,
15441                                InlineDiagnostic {
15442                                    message,
15443                                    group_id: diagnostic_entry.diagnostic.group_id,
15444                                    start: diagnostic_entry.range.start.to_point(&snapshot),
15445                                    is_primary: diagnostic_entry.diagnostic.is_primary,
15446                                    severity: diagnostic_entry.diagnostic.severity,
15447                                },
15448                            ),
15449                        );
15450                    }
15451                    inline_diagnostics
15452                })
15453                .await;
15454
15455            editor
15456                .update(cx, |editor, cx| {
15457                    editor.inline_diagnostics = new_inline_diagnostics;
15458                    cx.notify();
15459                })
15460                .ok();
15461        });
15462    }
15463
15464    pub fn set_selections_from_remote(
15465        &mut self,
15466        selections: Vec<Selection<Anchor>>,
15467        pending_selection: Option<Selection<Anchor>>,
15468        window: &mut Window,
15469        cx: &mut Context<Self>,
15470    ) {
15471        let old_cursor_position = self.selections.newest_anchor().head();
15472        self.selections.change_with(cx, |s| {
15473            s.select_anchors(selections);
15474            if let Some(pending_selection) = pending_selection {
15475                s.set_pending(pending_selection, SelectMode::Character);
15476            } else {
15477                s.clear_pending();
15478            }
15479        });
15480        self.selections_did_change(false, &old_cursor_position, true, window, cx);
15481    }
15482
15483    fn push_to_selection_history(&mut self) {
15484        self.selection_history.push(SelectionHistoryEntry {
15485            selections: self.selections.disjoint_anchors(),
15486            select_next_state: self.select_next_state.clone(),
15487            select_prev_state: self.select_prev_state.clone(),
15488            add_selections_state: self.add_selections_state.clone(),
15489        });
15490    }
15491
15492    pub fn transact(
15493        &mut self,
15494        window: &mut Window,
15495        cx: &mut Context<Self>,
15496        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
15497    ) -> Option<TransactionId> {
15498        self.start_transaction_at(Instant::now(), window, cx);
15499        update(self, window, cx);
15500        self.end_transaction_at(Instant::now(), cx)
15501    }
15502
15503    pub fn start_transaction_at(
15504        &mut self,
15505        now: Instant,
15506        window: &mut Window,
15507        cx: &mut Context<Self>,
15508    ) {
15509        self.end_selection(window, cx);
15510        if let Some(tx_id) = self
15511            .buffer
15512            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
15513        {
15514            self.selection_history
15515                .insert_transaction(tx_id, self.selections.disjoint_anchors());
15516            cx.emit(EditorEvent::TransactionBegun {
15517                transaction_id: tx_id,
15518            })
15519        }
15520    }
15521
15522    pub fn end_transaction_at(
15523        &mut self,
15524        now: Instant,
15525        cx: &mut Context<Self>,
15526    ) -> Option<TransactionId> {
15527        if let Some(transaction_id) = self
15528            .buffer
15529            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
15530        {
15531            if let Some((_, end_selections)) =
15532                self.selection_history.transaction_mut(transaction_id)
15533            {
15534                *end_selections = Some(self.selections.disjoint_anchors());
15535            } else {
15536                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
15537            }
15538
15539            cx.emit(EditorEvent::Edited { transaction_id });
15540            Some(transaction_id)
15541        } else {
15542            None
15543        }
15544    }
15545
15546    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
15547        if self.selection_mark_mode {
15548            self.change_selections(None, window, cx, |s| {
15549                s.move_with(|_, sel| {
15550                    sel.collapse_to(sel.head(), SelectionGoal::None);
15551                });
15552            })
15553        }
15554        self.selection_mark_mode = true;
15555        cx.notify();
15556    }
15557
15558    pub fn swap_selection_ends(
15559        &mut self,
15560        _: &actions::SwapSelectionEnds,
15561        window: &mut Window,
15562        cx: &mut Context<Self>,
15563    ) {
15564        self.change_selections(None, window, cx, |s| {
15565            s.move_with(|_, sel| {
15566                if sel.start != sel.end {
15567                    sel.reversed = !sel.reversed
15568                }
15569            });
15570        });
15571        self.request_autoscroll(Autoscroll::newest(), cx);
15572        cx.notify();
15573    }
15574
15575    pub fn toggle_fold(
15576        &mut self,
15577        _: &actions::ToggleFold,
15578        window: &mut Window,
15579        cx: &mut Context<Self>,
15580    ) {
15581        if self.is_singleton(cx) {
15582            let selection = self.selections.newest::<Point>(cx);
15583
15584            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15585            let range = if selection.is_empty() {
15586                let point = selection.head().to_display_point(&display_map);
15587                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15588                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15589                    .to_point(&display_map);
15590                start..end
15591            } else {
15592                selection.range()
15593            };
15594            if display_map.folds_in_range(range).next().is_some() {
15595                self.unfold_lines(&Default::default(), window, cx)
15596            } else {
15597                self.fold(&Default::default(), window, cx)
15598            }
15599        } else {
15600            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15601            let buffer_ids: HashSet<_> = self
15602                .selections
15603                .disjoint_anchor_ranges()
15604                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15605                .collect();
15606
15607            let should_unfold = buffer_ids
15608                .iter()
15609                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
15610
15611            for buffer_id in buffer_ids {
15612                if should_unfold {
15613                    self.unfold_buffer(buffer_id, cx);
15614                } else {
15615                    self.fold_buffer(buffer_id, cx);
15616                }
15617            }
15618        }
15619    }
15620
15621    pub fn toggle_fold_recursive(
15622        &mut self,
15623        _: &actions::ToggleFoldRecursive,
15624        window: &mut Window,
15625        cx: &mut Context<Self>,
15626    ) {
15627        let selection = self.selections.newest::<Point>(cx);
15628
15629        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15630        let range = if selection.is_empty() {
15631            let point = selection.head().to_display_point(&display_map);
15632            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15633            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15634                .to_point(&display_map);
15635            start..end
15636        } else {
15637            selection.range()
15638        };
15639        if display_map.folds_in_range(range).next().is_some() {
15640            self.unfold_recursive(&Default::default(), window, cx)
15641        } else {
15642            self.fold_recursive(&Default::default(), window, cx)
15643        }
15644    }
15645
15646    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
15647        if self.is_singleton(cx) {
15648            let mut to_fold = Vec::new();
15649            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15650            let selections = self.selections.all_adjusted(cx);
15651
15652            for selection in selections {
15653                let range = selection.range().sorted();
15654                let buffer_start_row = range.start.row;
15655
15656                if range.start.row != range.end.row {
15657                    let mut found = false;
15658                    let mut row = range.start.row;
15659                    while row <= range.end.row {
15660                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
15661                        {
15662                            found = true;
15663                            row = crease.range().end.row + 1;
15664                            to_fold.push(crease);
15665                        } else {
15666                            row += 1
15667                        }
15668                    }
15669                    if found {
15670                        continue;
15671                    }
15672                }
15673
15674                for row in (0..=range.start.row).rev() {
15675                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15676                        if crease.range().end.row >= buffer_start_row {
15677                            to_fold.push(crease);
15678                            if row <= range.start.row {
15679                                break;
15680                            }
15681                        }
15682                    }
15683                }
15684            }
15685
15686            self.fold_creases(to_fold, true, window, cx);
15687        } else {
15688            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15689            let buffer_ids = self
15690                .selections
15691                .disjoint_anchor_ranges()
15692                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15693                .collect::<HashSet<_>>();
15694            for buffer_id in buffer_ids {
15695                self.fold_buffer(buffer_id, cx);
15696            }
15697        }
15698    }
15699
15700    fn fold_at_level(
15701        &mut self,
15702        fold_at: &FoldAtLevel,
15703        window: &mut Window,
15704        cx: &mut Context<Self>,
15705    ) {
15706        if !self.buffer.read(cx).is_singleton() {
15707            return;
15708        }
15709
15710        let fold_at_level = fold_at.0;
15711        let snapshot = self.buffer.read(cx).snapshot(cx);
15712        let mut to_fold = Vec::new();
15713        let mut stack = vec![(0, snapshot.max_row().0, 1)];
15714
15715        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
15716            while start_row < end_row {
15717                match self
15718                    .snapshot(window, cx)
15719                    .crease_for_buffer_row(MultiBufferRow(start_row))
15720                {
15721                    Some(crease) => {
15722                        let nested_start_row = crease.range().start.row + 1;
15723                        let nested_end_row = crease.range().end.row;
15724
15725                        if current_level < fold_at_level {
15726                            stack.push((nested_start_row, nested_end_row, current_level + 1));
15727                        } else if current_level == fold_at_level {
15728                            to_fold.push(crease);
15729                        }
15730
15731                        start_row = nested_end_row + 1;
15732                    }
15733                    None => start_row += 1,
15734                }
15735            }
15736        }
15737
15738        self.fold_creases(to_fold, true, window, cx);
15739    }
15740
15741    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
15742        if self.buffer.read(cx).is_singleton() {
15743            let mut fold_ranges = Vec::new();
15744            let snapshot = self.buffer.read(cx).snapshot(cx);
15745
15746            for row in 0..snapshot.max_row().0 {
15747                if let Some(foldable_range) = self
15748                    .snapshot(window, cx)
15749                    .crease_for_buffer_row(MultiBufferRow(row))
15750                {
15751                    fold_ranges.push(foldable_range);
15752                }
15753            }
15754
15755            self.fold_creases(fold_ranges, true, window, cx);
15756        } else {
15757            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
15758                editor
15759                    .update_in(cx, |editor, _, cx| {
15760                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15761                            editor.fold_buffer(buffer_id, cx);
15762                        }
15763                    })
15764                    .ok();
15765            });
15766        }
15767    }
15768
15769    pub fn fold_function_bodies(
15770        &mut self,
15771        _: &actions::FoldFunctionBodies,
15772        window: &mut Window,
15773        cx: &mut Context<Self>,
15774    ) {
15775        let snapshot = self.buffer.read(cx).snapshot(cx);
15776
15777        let ranges = snapshot
15778            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
15779            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
15780            .collect::<Vec<_>>();
15781
15782        let creases = ranges
15783            .into_iter()
15784            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
15785            .collect();
15786
15787        self.fold_creases(creases, true, window, cx);
15788    }
15789
15790    pub fn fold_recursive(
15791        &mut self,
15792        _: &actions::FoldRecursive,
15793        window: &mut Window,
15794        cx: &mut Context<Self>,
15795    ) {
15796        let mut to_fold = Vec::new();
15797        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15798        let selections = self.selections.all_adjusted(cx);
15799
15800        for selection in selections {
15801            let range = selection.range().sorted();
15802            let buffer_start_row = range.start.row;
15803
15804            if range.start.row != range.end.row {
15805                let mut found = false;
15806                for row in range.start.row..=range.end.row {
15807                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15808                        found = true;
15809                        to_fold.push(crease);
15810                    }
15811                }
15812                if found {
15813                    continue;
15814                }
15815            }
15816
15817            for row in (0..=range.start.row).rev() {
15818                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15819                    if crease.range().end.row >= buffer_start_row {
15820                        to_fold.push(crease);
15821                    } else {
15822                        break;
15823                    }
15824                }
15825            }
15826        }
15827
15828        self.fold_creases(to_fold, true, window, cx);
15829    }
15830
15831    pub fn fold_at(
15832        &mut self,
15833        buffer_row: MultiBufferRow,
15834        window: &mut Window,
15835        cx: &mut Context<Self>,
15836    ) {
15837        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15838
15839        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
15840            let autoscroll = self
15841                .selections
15842                .all::<Point>(cx)
15843                .iter()
15844                .any(|selection| crease.range().overlaps(&selection.range()));
15845
15846            self.fold_creases(vec![crease], autoscroll, window, cx);
15847        }
15848    }
15849
15850    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
15851        if self.is_singleton(cx) {
15852            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15853            let buffer = &display_map.buffer_snapshot;
15854            let selections = self.selections.all::<Point>(cx);
15855            let ranges = selections
15856                .iter()
15857                .map(|s| {
15858                    let range = s.display_range(&display_map).sorted();
15859                    let mut start = range.start.to_point(&display_map);
15860                    let mut end = range.end.to_point(&display_map);
15861                    start.column = 0;
15862                    end.column = buffer.line_len(MultiBufferRow(end.row));
15863                    start..end
15864                })
15865                .collect::<Vec<_>>();
15866
15867            self.unfold_ranges(&ranges, true, true, cx);
15868        } else {
15869            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15870            let buffer_ids = self
15871                .selections
15872                .disjoint_anchor_ranges()
15873                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15874                .collect::<HashSet<_>>();
15875            for buffer_id in buffer_ids {
15876                self.unfold_buffer(buffer_id, cx);
15877            }
15878        }
15879    }
15880
15881    pub fn unfold_recursive(
15882        &mut self,
15883        _: &UnfoldRecursive,
15884        _window: &mut Window,
15885        cx: &mut Context<Self>,
15886    ) {
15887        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15888        let selections = self.selections.all::<Point>(cx);
15889        let ranges = selections
15890            .iter()
15891            .map(|s| {
15892                let mut range = s.display_range(&display_map).sorted();
15893                *range.start.column_mut() = 0;
15894                *range.end.column_mut() = display_map.line_len(range.end.row());
15895                let start = range.start.to_point(&display_map);
15896                let end = range.end.to_point(&display_map);
15897                start..end
15898            })
15899            .collect::<Vec<_>>();
15900
15901        self.unfold_ranges(&ranges, true, true, cx);
15902    }
15903
15904    pub fn unfold_at(
15905        &mut self,
15906        buffer_row: MultiBufferRow,
15907        _window: &mut Window,
15908        cx: &mut Context<Self>,
15909    ) {
15910        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15911
15912        let intersection_range = Point::new(buffer_row.0, 0)
15913            ..Point::new(
15914                buffer_row.0,
15915                display_map.buffer_snapshot.line_len(buffer_row),
15916            );
15917
15918        let autoscroll = self
15919            .selections
15920            .all::<Point>(cx)
15921            .iter()
15922            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
15923
15924        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
15925    }
15926
15927    pub fn unfold_all(
15928        &mut self,
15929        _: &actions::UnfoldAll,
15930        _window: &mut Window,
15931        cx: &mut Context<Self>,
15932    ) {
15933        if self.buffer.read(cx).is_singleton() {
15934            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15935            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
15936        } else {
15937            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
15938                editor
15939                    .update(cx, |editor, cx| {
15940                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15941                            editor.unfold_buffer(buffer_id, cx);
15942                        }
15943                    })
15944                    .ok();
15945            });
15946        }
15947    }
15948
15949    pub fn fold_selected_ranges(
15950        &mut self,
15951        _: &FoldSelectedRanges,
15952        window: &mut Window,
15953        cx: &mut Context<Self>,
15954    ) {
15955        let selections = self.selections.all_adjusted(cx);
15956        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15957        let ranges = selections
15958            .into_iter()
15959            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
15960            .collect::<Vec<_>>();
15961        self.fold_creases(ranges, true, window, cx);
15962    }
15963
15964    pub fn fold_ranges<T: ToOffset + Clone>(
15965        &mut self,
15966        ranges: Vec<Range<T>>,
15967        auto_scroll: bool,
15968        window: &mut Window,
15969        cx: &mut Context<Self>,
15970    ) {
15971        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15972        let ranges = ranges
15973            .into_iter()
15974            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
15975            .collect::<Vec<_>>();
15976        self.fold_creases(ranges, auto_scroll, window, cx);
15977    }
15978
15979    pub fn fold_creases<T: ToOffset + Clone>(
15980        &mut self,
15981        creases: Vec<Crease<T>>,
15982        auto_scroll: bool,
15983        _window: &mut Window,
15984        cx: &mut Context<Self>,
15985    ) {
15986        if creases.is_empty() {
15987            return;
15988        }
15989
15990        let mut buffers_affected = HashSet::default();
15991        let multi_buffer = self.buffer().read(cx);
15992        for crease in &creases {
15993            if let Some((_, buffer, _)) =
15994                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
15995            {
15996                buffers_affected.insert(buffer.read(cx).remote_id());
15997            };
15998        }
15999
16000        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16001
16002        if auto_scroll {
16003            self.request_autoscroll(Autoscroll::fit(), cx);
16004        }
16005
16006        cx.notify();
16007
16008        self.scrollbar_marker_state.dirty = true;
16009        self.folds_did_change(cx);
16010    }
16011
16012    /// Removes any folds whose ranges intersect any of the given ranges.
16013    pub fn unfold_ranges<T: ToOffset + Clone>(
16014        &mut self,
16015        ranges: &[Range<T>],
16016        inclusive: bool,
16017        auto_scroll: bool,
16018        cx: &mut Context<Self>,
16019    ) {
16020        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16021            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16022        });
16023        self.folds_did_change(cx);
16024    }
16025
16026    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16027        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16028            return;
16029        }
16030        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16031        self.display_map.update(cx, |display_map, cx| {
16032            display_map.fold_buffers([buffer_id], cx)
16033        });
16034        cx.emit(EditorEvent::BufferFoldToggled {
16035            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16036            folded: true,
16037        });
16038        cx.notify();
16039    }
16040
16041    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16042        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16043            return;
16044        }
16045        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16046        self.display_map.update(cx, |display_map, cx| {
16047            display_map.unfold_buffers([buffer_id], cx);
16048        });
16049        cx.emit(EditorEvent::BufferFoldToggled {
16050            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16051            folded: false,
16052        });
16053        cx.notify();
16054    }
16055
16056    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16057        self.display_map.read(cx).is_buffer_folded(buffer)
16058    }
16059
16060    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16061        self.display_map.read(cx).folded_buffers()
16062    }
16063
16064    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16065        self.display_map.update(cx, |display_map, cx| {
16066            display_map.disable_header_for_buffer(buffer_id, cx);
16067        });
16068        cx.notify();
16069    }
16070
16071    /// Removes any folds with the given ranges.
16072    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16073        &mut self,
16074        ranges: &[Range<T>],
16075        type_id: TypeId,
16076        auto_scroll: bool,
16077        cx: &mut Context<Self>,
16078    ) {
16079        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16080            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16081        });
16082        self.folds_did_change(cx);
16083    }
16084
16085    fn remove_folds_with<T: ToOffset + Clone>(
16086        &mut self,
16087        ranges: &[Range<T>],
16088        auto_scroll: bool,
16089        cx: &mut Context<Self>,
16090        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16091    ) {
16092        if ranges.is_empty() {
16093            return;
16094        }
16095
16096        let mut buffers_affected = HashSet::default();
16097        let multi_buffer = self.buffer().read(cx);
16098        for range in ranges {
16099            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16100                buffers_affected.insert(buffer.read(cx).remote_id());
16101            };
16102        }
16103
16104        self.display_map.update(cx, update);
16105
16106        if auto_scroll {
16107            self.request_autoscroll(Autoscroll::fit(), cx);
16108        }
16109
16110        cx.notify();
16111        self.scrollbar_marker_state.dirty = true;
16112        self.active_indent_guides_state.dirty = true;
16113    }
16114
16115    pub fn update_fold_widths(
16116        &mut self,
16117        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16118        cx: &mut Context<Self>,
16119    ) -> bool {
16120        self.display_map
16121            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16122    }
16123
16124    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16125        self.display_map.read(cx).fold_placeholder.clone()
16126    }
16127
16128    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16129        self.buffer.update(cx, |buffer, cx| {
16130            buffer.set_all_diff_hunks_expanded(cx);
16131        });
16132    }
16133
16134    pub fn expand_all_diff_hunks(
16135        &mut self,
16136        _: &ExpandAllDiffHunks,
16137        _window: &mut Window,
16138        cx: &mut Context<Self>,
16139    ) {
16140        self.buffer.update(cx, |buffer, cx| {
16141            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16142        });
16143    }
16144
16145    pub fn toggle_selected_diff_hunks(
16146        &mut self,
16147        _: &ToggleSelectedDiffHunks,
16148        _window: &mut Window,
16149        cx: &mut Context<Self>,
16150    ) {
16151        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16152        self.toggle_diff_hunks_in_ranges(ranges, cx);
16153    }
16154
16155    pub fn diff_hunks_in_ranges<'a>(
16156        &'a self,
16157        ranges: &'a [Range<Anchor>],
16158        buffer: &'a MultiBufferSnapshot,
16159    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16160        ranges.iter().flat_map(move |range| {
16161            let end_excerpt_id = range.end.excerpt_id;
16162            let range = range.to_point(buffer);
16163            let mut peek_end = range.end;
16164            if range.end.row < buffer.max_row().0 {
16165                peek_end = Point::new(range.end.row + 1, 0);
16166            }
16167            buffer
16168                .diff_hunks_in_range(range.start..peek_end)
16169                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16170        })
16171    }
16172
16173    pub fn has_stageable_diff_hunks_in_ranges(
16174        &self,
16175        ranges: &[Range<Anchor>],
16176        snapshot: &MultiBufferSnapshot,
16177    ) -> bool {
16178        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16179        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16180    }
16181
16182    pub fn toggle_staged_selected_diff_hunks(
16183        &mut self,
16184        _: &::git::ToggleStaged,
16185        _: &mut Window,
16186        cx: &mut Context<Self>,
16187    ) {
16188        let snapshot = self.buffer.read(cx).snapshot(cx);
16189        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16190        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16191        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16192    }
16193
16194    pub fn set_render_diff_hunk_controls(
16195        &mut self,
16196        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16197        cx: &mut Context<Self>,
16198    ) {
16199        self.render_diff_hunk_controls = render_diff_hunk_controls;
16200        cx.notify();
16201    }
16202
16203    pub fn stage_and_next(
16204        &mut self,
16205        _: &::git::StageAndNext,
16206        window: &mut Window,
16207        cx: &mut Context<Self>,
16208    ) {
16209        self.do_stage_or_unstage_and_next(true, window, cx);
16210    }
16211
16212    pub fn unstage_and_next(
16213        &mut self,
16214        _: &::git::UnstageAndNext,
16215        window: &mut Window,
16216        cx: &mut Context<Self>,
16217    ) {
16218        self.do_stage_or_unstage_and_next(false, window, cx);
16219    }
16220
16221    pub fn stage_or_unstage_diff_hunks(
16222        &mut self,
16223        stage: bool,
16224        ranges: Vec<Range<Anchor>>,
16225        cx: &mut Context<Self>,
16226    ) {
16227        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16228        cx.spawn(async move |this, cx| {
16229            task.await?;
16230            this.update(cx, |this, cx| {
16231                let snapshot = this.buffer.read(cx).snapshot(cx);
16232                let chunk_by = this
16233                    .diff_hunks_in_ranges(&ranges, &snapshot)
16234                    .chunk_by(|hunk| hunk.buffer_id);
16235                for (buffer_id, hunks) in &chunk_by {
16236                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16237                }
16238            })
16239        })
16240        .detach_and_log_err(cx);
16241    }
16242
16243    fn save_buffers_for_ranges_if_needed(
16244        &mut self,
16245        ranges: &[Range<Anchor>],
16246        cx: &mut Context<Editor>,
16247    ) -> Task<Result<()>> {
16248        let multibuffer = self.buffer.read(cx);
16249        let snapshot = multibuffer.read(cx);
16250        let buffer_ids: HashSet<_> = ranges
16251            .iter()
16252            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16253            .collect();
16254        drop(snapshot);
16255
16256        let mut buffers = HashSet::default();
16257        for buffer_id in buffer_ids {
16258            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16259                let buffer = buffer_entity.read(cx);
16260                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16261                {
16262                    buffers.insert(buffer_entity);
16263                }
16264            }
16265        }
16266
16267        if let Some(project) = &self.project {
16268            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16269        } else {
16270            Task::ready(Ok(()))
16271        }
16272    }
16273
16274    fn do_stage_or_unstage_and_next(
16275        &mut self,
16276        stage: bool,
16277        window: &mut Window,
16278        cx: &mut Context<Self>,
16279    ) {
16280        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16281
16282        if ranges.iter().any(|range| range.start != range.end) {
16283            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16284            return;
16285        }
16286
16287        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16288        let snapshot = self.snapshot(window, cx);
16289        let position = self.selections.newest::<Point>(cx).head();
16290        let mut row = snapshot
16291            .buffer_snapshot
16292            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16293            .find(|hunk| hunk.row_range.start.0 > position.row)
16294            .map(|hunk| hunk.row_range.start);
16295
16296        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16297        // Outside of the project diff editor, wrap around to the beginning.
16298        if !all_diff_hunks_expanded {
16299            row = row.or_else(|| {
16300                snapshot
16301                    .buffer_snapshot
16302                    .diff_hunks_in_range(Point::zero()..position)
16303                    .find(|hunk| hunk.row_range.end.0 < position.row)
16304                    .map(|hunk| hunk.row_range.start)
16305            });
16306        }
16307
16308        if let Some(row) = row {
16309            let destination = Point::new(row.0, 0);
16310            let autoscroll = Autoscroll::center();
16311
16312            self.unfold_ranges(&[destination..destination], false, false, cx);
16313            self.change_selections(Some(autoscroll), window, cx, |s| {
16314                s.select_ranges([destination..destination]);
16315            });
16316        }
16317    }
16318
16319    fn do_stage_or_unstage(
16320        &self,
16321        stage: bool,
16322        buffer_id: BufferId,
16323        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
16324        cx: &mut App,
16325    ) -> Option<()> {
16326        let project = self.project.as_ref()?;
16327        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
16328        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
16329        let buffer_snapshot = buffer.read(cx).snapshot();
16330        let file_exists = buffer_snapshot
16331            .file()
16332            .is_some_and(|file| file.disk_state().exists());
16333        diff.update(cx, |diff, cx| {
16334            diff.stage_or_unstage_hunks(
16335                stage,
16336                &hunks
16337                    .map(|hunk| buffer_diff::DiffHunk {
16338                        buffer_range: hunk.buffer_range,
16339                        diff_base_byte_range: hunk.diff_base_byte_range,
16340                        secondary_status: hunk.secondary_status,
16341                        range: Point::zero()..Point::zero(), // unused
16342                    })
16343                    .collect::<Vec<_>>(),
16344                &buffer_snapshot,
16345                file_exists,
16346                cx,
16347            )
16348        });
16349        None
16350    }
16351
16352    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
16353        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16354        self.buffer
16355            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
16356    }
16357
16358    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
16359        self.buffer.update(cx, |buffer, cx| {
16360            let ranges = vec![Anchor::min()..Anchor::max()];
16361            if !buffer.all_diff_hunks_expanded()
16362                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
16363            {
16364                buffer.collapse_diff_hunks(ranges, cx);
16365                true
16366            } else {
16367                false
16368            }
16369        })
16370    }
16371
16372    fn toggle_diff_hunks_in_ranges(
16373        &mut self,
16374        ranges: Vec<Range<Anchor>>,
16375        cx: &mut Context<Editor>,
16376    ) {
16377        self.buffer.update(cx, |buffer, cx| {
16378            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
16379            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
16380        })
16381    }
16382
16383    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
16384        self.buffer.update(cx, |buffer, cx| {
16385            let snapshot = buffer.snapshot(cx);
16386            let excerpt_id = range.end.excerpt_id;
16387            let point_range = range.to_point(&snapshot);
16388            let expand = !buffer.single_hunk_is_expanded(range, cx);
16389            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
16390        })
16391    }
16392
16393    pub(crate) fn apply_all_diff_hunks(
16394        &mut self,
16395        _: &ApplyAllDiffHunks,
16396        window: &mut Window,
16397        cx: &mut Context<Self>,
16398    ) {
16399        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16400
16401        let buffers = self.buffer.read(cx).all_buffers();
16402        for branch_buffer in buffers {
16403            branch_buffer.update(cx, |branch_buffer, cx| {
16404                branch_buffer.merge_into_base(Vec::new(), cx);
16405            });
16406        }
16407
16408        if let Some(project) = self.project.clone() {
16409            self.save(true, project, window, cx).detach_and_log_err(cx);
16410        }
16411    }
16412
16413    pub(crate) fn apply_selected_diff_hunks(
16414        &mut self,
16415        _: &ApplyDiffHunk,
16416        window: &mut Window,
16417        cx: &mut Context<Self>,
16418    ) {
16419        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16420        let snapshot = self.snapshot(window, cx);
16421        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
16422        let mut ranges_by_buffer = HashMap::default();
16423        self.transact(window, cx, |editor, _window, cx| {
16424            for hunk in hunks {
16425                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
16426                    ranges_by_buffer
16427                        .entry(buffer.clone())
16428                        .or_insert_with(Vec::new)
16429                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
16430                }
16431            }
16432
16433            for (buffer, ranges) in ranges_by_buffer {
16434                buffer.update(cx, |buffer, cx| {
16435                    buffer.merge_into_base(ranges, cx);
16436                });
16437            }
16438        });
16439
16440        if let Some(project) = self.project.clone() {
16441            self.save(true, project, window, cx).detach_and_log_err(cx);
16442        }
16443    }
16444
16445    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
16446        if hovered != self.gutter_hovered {
16447            self.gutter_hovered = hovered;
16448            cx.notify();
16449        }
16450    }
16451
16452    pub fn insert_blocks(
16453        &mut self,
16454        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
16455        autoscroll: Option<Autoscroll>,
16456        cx: &mut Context<Self>,
16457    ) -> Vec<CustomBlockId> {
16458        let blocks = self
16459            .display_map
16460            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
16461        if let Some(autoscroll) = autoscroll {
16462            self.request_autoscroll(autoscroll, cx);
16463        }
16464        cx.notify();
16465        blocks
16466    }
16467
16468    pub fn resize_blocks(
16469        &mut self,
16470        heights: HashMap<CustomBlockId, u32>,
16471        autoscroll: Option<Autoscroll>,
16472        cx: &mut Context<Self>,
16473    ) {
16474        self.display_map
16475            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
16476        if let Some(autoscroll) = autoscroll {
16477            self.request_autoscroll(autoscroll, cx);
16478        }
16479        cx.notify();
16480    }
16481
16482    pub fn replace_blocks(
16483        &mut self,
16484        renderers: HashMap<CustomBlockId, RenderBlock>,
16485        autoscroll: Option<Autoscroll>,
16486        cx: &mut Context<Self>,
16487    ) {
16488        self.display_map
16489            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
16490        if let Some(autoscroll) = autoscroll {
16491            self.request_autoscroll(autoscroll, cx);
16492        }
16493        cx.notify();
16494    }
16495
16496    pub fn remove_blocks(
16497        &mut self,
16498        block_ids: HashSet<CustomBlockId>,
16499        autoscroll: Option<Autoscroll>,
16500        cx: &mut Context<Self>,
16501    ) {
16502        self.display_map.update(cx, |display_map, cx| {
16503            display_map.remove_blocks(block_ids, cx)
16504        });
16505        if let Some(autoscroll) = autoscroll {
16506            self.request_autoscroll(autoscroll, cx);
16507        }
16508        cx.notify();
16509    }
16510
16511    pub fn row_for_block(
16512        &self,
16513        block_id: CustomBlockId,
16514        cx: &mut Context<Self>,
16515    ) -> Option<DisplayRow> {
16516        self.display_map
16517            .update(cx, |map, cx| map.row_for_block(block_id, cx))
16518    }
16519
16520    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
16521        self.focused_block = Some(focused_block);
16522    }
16523
16524    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
16525        self.focused_block.take()
16526    }
16527
16528    pub fn insert_creases(
16529        &mut self,
16530        creases: impl IntoIterator<Item = Crease<Anchor>>,
16531        cx: &mut Context<Self>,
16532    ) -> Vec<CreaseId> {
16533        self.display_map
16534            .update(cx, |map, cx| map.insert_creases(creases, cx))
16535    }
16536
16537    pub fn remove_creases(
16538        &mut self,
16539        ids: impl IntoIterator<Item = CreaseId>,
16540        cx: &mut Context<Self>,
16541    ) -> Vec<(CreaseId, Range<Anchor>)> {
16542        self.display_map
16543            .update(cx, |map, cx| map.remove_creases(ids, cx))
16544    }
16545
16546    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
16547        self.display_map
16548            .update(cx, |map, cx| map.snapshot(cx))
16549            .longest_row()
16550    }
16551
16552    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
16553        self.display_map
16554            .update(cx, |map, cx| map.snapshot(cx))
16555            .max_point()
16556    }
16557
16558    pub fn text(&self, cx: &App) -> String {
16559        self.buffer.read(cx).read(cx).text()
16560    }
16561
16562    pub fn is_empty(&self, cx: &App) -> bool {
16563        self.buffer.read(cx).read(cx).is_empty()
16564    }
16565
16566    pub fn text_option(&self, cx: &App) -> Option<String> {
16567        let text = self.text(cx);
16568        let text = text.trim();
16569
16570        if text.is_empty() {
16571            return None;
16572        }
16573
16574        Some(text.to_string())
16575    }
16576
16577    pub fn set_text(
16578        &mut self,
16579        text: impl Into<Arc<str>>,
16580        window: &mut Window,
16581        cx: &mut Context<Self>,
16582    ) {
16583        self.transact(window, cx, |this, _, cx| {
16584            this.buffer
16585                .read(cx)
16586                .as_singleton()
16587                .expect("you can only call set_text on editors for singleton buffers")
16588                .update(cx, |buffer, cx| buffer.set_text(text, cx));
16589        });
16590    }
16591
16592    pub fn display_text(&self, cx: &mut App) -> String {
16593        self.display_map
16594            .update(cx, |map, cx| map.snapshot(cx))
16595            .text()
16596    }
16597
16598    fn create_minimap(
16599        &self,
16600        minimap_settings: MinimapSettings,
16601        window: &mut Window,
16602        cx: &mut Context<Self>,
16603    ) -> Option<Entity<Self>> {
16604        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
16605            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
16606    }
16607
16608    fn initialize_new_minimap(
16609        &self,
16610        minimap_settings: MinimapSettings,
16611        window: &mut Window,
16612        cx: &mut Context<Self>,
16613    ) -> Entity<Self> {
16614        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
16615
16616        let mut minimap = Editor::new_internal(
16617            EditorMode::Minimap {
16618                parent: cx.weak_entity(),
16619            },
16620            self.buffer.clone(),
16621            self.project.clone(),
16622            Some(self.display_map.clone()),
16623            window,
16624            cx,
16625        );
16626        minimap.scroll_manager.clone_state(&self.scroll_manager);
16627        minimap.set_text_style_refinement(TextStyleRefinement {
16628            font_size: Some(MINIMAP_FONT_SIZE),
16629            font_weight: Some(MINIMAP_FONT_WEIGHT),
16630            ..Default::default()
16631        });
16632        minimap.update_minimap_configuration(minimap_settings, cx);
16633        cx.new(|_| minimap)
16634    }
16635
16636    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
16637        let current_line_highlight = minimap_settings
16638            .current_line_highlight
16639            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
16640        self.set_current_line_highlight(Some(current_line_highlight));
16641    }
16642
16643    pub fn minimap(&self) -> Option<&Entity<Self>> {
16644        self.minimap
16645            .as_ref()
16646            .filter(|_| self.minimap_visibility.visible())
16647    }
16648
16649    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
16650        let mut wrap_guides = smallvec::smallvec![];
16651
16652        if self.show_wrap_guides == Some(false) {
16653            return wrap_guides;
16654        }
16655
16656        let settings = self.buffer.read(cx).language_settings(cx);
16657        if settings.show_wrap_guides {
16658            match self.soft_wrap_mode(cx) {
16659                SoftWrap::Column(soft_wrap) => {
16660                    wrap_guides.push((soft_wrap as usize, true));
16661                }
16662                SoftWrap::Bounded(soft_wrap) => {
16663                    wrap_guides.push((soft_wrap as usize, true));
16664                }
16665                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
16666            }
16667            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
16668        }
16669
16670        wrap_guides
16671    }
16672
16673    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
16674        let settings = self.buffer.read(cx).language_settings(cx);
16675        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
16676        match mode {
16677            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
16678                SoftWrap::None
16679            }
16680            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
16681            language_settings::SoftWrap::PreferredLineLength => {
16682                SoftWrap::Column(settings.preferred_line_length)
16683            }
16684            language_settings::SoftWrap::Bounded => {
16685                SoftWrap::Bounded(settings.preferred_line_length)
16686            }
16687        }
16688    }
16689
16690    pub fn set_soft_wrap_mode(
16691        &mut self,
16692        mode: language_settings::SoftWrap,
16693
16694        cx: &mut Context<Self>,
16695    ) {
16696        self.soft_wrap_mode_override = Some(mode);
16697        cx.notify();
16698    }
16699
16700    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
16701        self.hard_wrap = hard_wrap;
16702        cx.notify();
16703    }
16704
16705    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
16706        self.text_style_refinement = Some(style);
16707    }
16708
16709    /// called by the Element so we know what style we were most recently rendered with.
16710    pub(crate) fn set_style(
16711        &mut self,
16712        style: EditorStyle,
16713        window: &mut Window,
16714        cx: &mut Context<Self>,
16715    ) {
16716        // We intentionally do not inform the display map about the minimap style
16717        // so that wrapping is not recalculated and stays consistent for the editor
16718        // and its linked minimap.
16719        if !self.mode.is_minimap() {
16720            let rem_size = window.rem_size();
16721            self.display_map.update(cx, |map, cx| {
16722                map.set_font(
16723                    style.text.font(),
16724                    style.text.font_size.to_pixels(rem_size),
16725                    cx,
16726                )
16727            });
16728        }
16729        self.style = Some(style);
16730    }
16731
16732    pub fn style(&self) -> Option<&EditorStyle> {
16733        self.style.as_ref()
16734    }
16735
16736    // Called by the element. This method is not designed to be called outside of the editor
16737    // element's layout code because it does not notify when rewrapping is computed synchronously.
16738    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
16739        self.display_map
16740            .update(cx, |map, cx| map.set_wrap_width(width, cx))
16741    }
16742
16743    pub fn set_soft_wrap(&mut self) {
16744        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
16745    }
16746
16747    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
16748        if self.soft_wrap_mode_override.is_some() {
16749            self.soft_wrap_mode_override.take();
16750        } else {
16751            let soft_wrap = match self.soft_wrap_mode(cx) {
16752                SoftWrap::GitDiff => return,
16753                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
16754                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
16755                    language_settings::SoftWrap::None
16756                }
16757            };
16758            self.soft_wrap_mode_override = Some(soft_wrap);
16759        }
16760        cx.notify();
16761    }
16762
16763    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
16764        let Some(workspace) = self.workspace() else {
16765            return;
16766        };
16767        let fs = workspace.read(cx).app_state().fs.clone();
16768        let current_show = TabBarSettings::get_global(cx).show;
16769        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
16770            setting.show = Some(!current_show);
16771        });
16772    }
16773
16774    pub fn toggle_indent_guides(
16775        &mut self,
16776        _: &ToggleIndentGuides,
16777        _: &mut Window,
16778        cx: &mut Context<Self>,
16779    ) {
16780        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
16781            self.buffer
16782                .read(cx)
16783                .language_settings(cx)
16784                .indent_guides
16785                .enabled
16786        });
16787        self.show_indent_guides = Some(!currently_enabled);
16788        cx.notify();
16789    }
16790
16791    fn should_show_indent_guides(&self) -> Option<bool> {
16792        self.show_indent_guides
16793    }
16794
16795    pub fn toggle_line_numbers(
16796        &mut self,
16797        _: &ToggleLineNumbers,
16798        _: &mut Window,
16799        cx: &mut Context<Self>,
16800    ) {
16801        let mut editor_settings = EditorSettings::get_global(cx).clone();
16802        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
16803        EditorSettings::override_global(editor_settings, cx);
16804    }
16805
16806    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
16807        if let Some(show_line_numbers) = self.show_line_numbers {
16808            return show_line_numbers;
16809        }
16810        EditorSettings::get_global(cx).gutter.line_numbers
16811    }
16812
16813    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
16814        self.use_relative_line_numbers
16815            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
16816    }
16817
16818    pub fn toggle_relative_line_numbers(
16819        &mut self,
16820        _: &ToggleRelativeLineNumbers,
16821        _: &mut Window,
16822        cx: &mut Context<Self>,
16823    ) {
16824        let is_relative = self.should_use_relative_line_numbers(cx);
16825        self.set_relative_line_number(Some(!is_relative), cx)
16826    }
16827
16828    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
16829        self.use_relative_line_numbers = is_relative;
16830        cx.notify();
16831    }
16832
16833    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
16834        self.show_gutter = show_gutter;
16835        cx.notify();
16836    }
16837
16838    pub fn set_show_scrollbars(&mut self, show_scrollbars: bool, cx: &mut Context<Self>) {
16839        self.show_scrollbars = show_scrollbars;
16840        cx.notify();
16841    }
16842
16843    pub fn set_minimap_visibility(
16844        &mut self,
16845        minimap_visibility: MinimapVisibility,
16846        window: &mut Window,
16847        cx: &mut Context<Self>,
16848    ) {
16849        if self.minimap_visibility != minimap_visibility {
16850            if minimap_visibility.visible() && self.minimap.is_none() {
16851                let minimap_settings = EditorSettings::get_global(cx).minimap;
16852                self.minimap =
16853                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
16854            }
16855            self.minimap_visibility = minimap_visibility;
16856            cx.notify();
16857        }
16858    }
16859
16860    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
16861        self.set_show_scrollbars(false, cx);
16862        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
16863    }
16864
16865    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
16866        self.show_line_numbers = Some(show_line_numbers);
16867        cx.notify();
16868    }
16869
16870    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
16871        self.disable_expand_excerpt_buttons = true;
16872        cx.notify();
16873    }
16874
16875    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
16876        self.show_git_diff_gutter = Some(show_git_diff_gutter);
16877        cx.notify();
16878    }
16879
16880    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
16881        self.show_code_actions = Some(show_code_actions);
16882        cx.notify();
16883    }
16884
16885    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
16886        self.show_runnables = Some(show_runnables);
16887        cx.notify();
16888    }
16889
16890    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
16891        self.show_breakpoints = Some(show_breakpoints);
16892        cx.notify();
16893    }
16894
16895    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
16896        if self.display_map.read(cx).masked != masked {
16897            self.display_map.update(cx, |map, _| map.masked = masked);
16898        }
16899        cx.notify()
16900    }
16901
16902    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
16903        self.show_wrap_guides = Some(show_wrap_guides);
16904        cx.notify();
16905    }
16906
16907    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
16908        self.show_indent_guides = Some(show_indent_guides);
16909        cx.notify();
16910    }
16911
16912    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
16913        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
16914            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
16915                if let Some(dir) = file.abs_path(cx).parent() {
16916                    return Some(dir.to_owned());
16917                }
16918            }
16919
16920            if let Some(project_path) = buffer.read(cx).project_path(cx) {
16921                return Some(project_path.path.to_path_buf());
16922            }
16923        }
16924
16925        None
16926    }
16927
16928    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
16929        self.active_excerpt(cx)?
16930            .1
16931            .read(cx)
16932            .file()
16933            .and_then(|f| f.as_local())
16934    }
16935
16936    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
16937        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
16938            let buffer = buffer.read(cx);
16939            if let Some(project_path) = buffer.project_path(cx) {
16940                let project = self.project.as_ref()?.read(cx);
16941                project.absolute_path(&project_path, cx)
16942            } else {
16943                buffer
16944                    .file()
16945                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
16946            }
16947        })
16948    }
16949
16950    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
16951        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
16952            let project_path = buffer.read(cx).project_path(cx)?;
16953            let project = self.project.as_ref()?.read(cx);
16954            let entry = project.entry_for_path(&project_path, cx)?;
16955            let path = entry.path.to_path_buf();
16956            Some(path)
16957        })
16958    }
16959
16960    pub fn reveal_in_finder(
16961        &mut self,
16962        _: &RevealInFileManager,
16963        _window: &mut Window,
16964        cx: &mut Context<Self>,
16965    ) {
16966        if let Some(target) = self.target_file(cx) {
16967            cx.reveal_path(&target.abs_path(cx));
16968        }
16969    }
16970
16971    pub fn copy_path(
16972        &mut self,
16973        _: &zed_actions::workspace::CopyPath,
16974        _window: &mut Window,
16975        cx: &mut Context<Self>,
16976    ) {
16977        if let Some(path) = self.target_file_abs_path(cx) {
16978            if let Some(path) = path.to_str() {
16979                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
16980            }
16981        }
16982    }
16983
16984    pub fn copy_relative_path(
16985        &mut self,
16986        _: &zed_actions::workspace::CopyRelativePath,
16987        _window: &mut Window,
16988        cx: &mut Context<Self>,
16989    ) {
16990        if let Some(path) = self.target_file_path(cx) {
16991            if let Some(path) = path.to_str() {
16992                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
16993            }
16994        }
16995    }
16996
16997    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
16998        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
16999            buffer.read(cx).project_path(cx)
17000        } else {
17001            None
17002        }
17003    }
17004
17005    // Returns true if the editor handled a go-to-line request
17006    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17007        maybe!({
17008            let breakpoint_store = self.breakpoint_store.as_ref()?;
17009
17010            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17011            else {
17012                self.clear_row_highlights::<ActiveDebugLine>();
17013                return None;
17014            };
17015
17016            let position = active_stack_frame.position;
17017            let buffer_id = position.buffer_id?;
17018            let snapshot = self
17019                .project
17020                .as_ref()?
17021                .read(cx)
17022                .buffer_for_id(buffer_id, cx)?
17023                .read(cx)
17024                .snapshot();
17025
17026            let mut handled = false;
17027            for (id, ExcerptRange { context, .. }) in
17028                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17029            {
17030                if context.start.cmp(&position, &snapshot).is_ge()
17031                    || context.end.cmp(&position, &snapshot).is_lt()
17032                {
17033                    continue;
17034                }
17035                let snapshot = self.buffer.read(cx).snapshot(cx);
17036                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17037
17038                handled = true;
17039                self.clear_row_highlights::<ActiveDebugLine>();
17040
17041                self.go_to_line::<ActiveDebugLine>(
17042                    multibuffer_anchor,
17043                    Some(cx.theme().colors().editor_debugger_active_line_background),
17044                    window,
17045                    cx,
17046                );
17047
17048                cx.notify();
17049            }
17050
17051            handled.then_some(())
17052        })
17053        .is_some()
17054    }
17055
17056    pub fn copy_file_name_without_extension(
17057        &mut self,
17058        _: &CopyFileNameWithoutExtension,
17059        _: &mut Window,
17060        cx: &mut Context<Self>,
17061    ) {
17062        if let Some(file) = self.target_file(cx) {
17063            if let Some(file_stem) = file.path().file_stem() {
17064                if let Some(name) = file_stem.to_str() {
17065                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17066                }
17067            }
17068        }
17069    }
17070
17071    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17072        if let Some(file) = self.target_file(cx) {
17073            if let Some(file_name) = file.path().file_name() {
17074                if let Some(name) = file_name.to_str() {
17075                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17076                }
17077            }
17078        }
17079    }
17080
17081    pub fn toggle_git_blame(
17082        &mut self,
17083        _: &::git::Blame,
17084        window: &mut Window,
17085        cx: &mut Context<Self>,
17086    ) {
17087        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17088
17089        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17090            self.start_git_blame(true, window, cx);
17091        }
17092
17093        cx.notify();
17094    }
17095
17096    pub fn toggle_git_blame_inline(
17097        &mut self,
17098        _: &ToggleGitBlameInline,
17099        window: &mut Window,
17100        cx: &mut Context<Self>,
17101    ) {
17102        self.toggle_git_blame_inline_internal(true, window, cx);
17103        cx.notify();
17104    }
17105
17106    pub fn open_git_blame_commit(
17107        &mut self,
17108        _: &OpenGitBlameCommit,
17109        window: &mut Window,
17110        cx: &mut Context<Self>,
17111    ) {
17112        self.open_git_blame_commit_internal(window, cx);
17113    }
17114
17115    fn open_git_blame_commit_internal(
17116        &mut self,
17117        window: &mut Window,
17118        cx: &mut Context<Self>,
17119    ) -> Option<()> {
17120        let blame = self.blame.as_ref()?;
17121        let snapshot = self.snapshot(window, cx);
17122        let cursor = self.selections.newest::<Point>(cx).head();
17123        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17124        let blame_entry = blame
17125            .update(cx, |blame, cx| {
17126                blame
17127                    .blame_for_rows(
17128                        &[RowInfo {
17129                            buffer_id: Some(buffer.remote_id()),
17130                            buffer_row: Some(point.row),
17131                            ..Default::default()
17132                        }],
17133                        cx,
17134                    )
17135                    .next()
17136            })
17137            .flatten()?;
17138        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17139        let repo = blame.read(cx).repository(cx)?;
17140        let workspace = self.workspace()?.downgrade();
17141        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17142        None
17143    }
17144
17145    pub fn git_blame_inline_enabled(&self) -> bool {
17146        self.git_blame_inline_enabled
17147    }
17148
17149    pub fn toggle_selection_menu(
17150        &mut self,
17151        _: &ToggleSelectionMenu,
17152        _: &mut Window,
17153        cx: &mut Context<Self>,
17154    ) {
17155        self.show_selection_menu = self
17156            .show_selection_menu
17157            .map(|show_selections_menu| !show_selections_menu)
17158            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17159
17160        cx.notify();
17161    }
17162
17163    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17164        self.show_selection_menu
17165            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17166    }
17167
17168    fn start_git_blame(
17169        &mut self,
17170        user_triggered: bool,
17171        window: &mut Window,
17172        cx: &mut Context<Self>,
17173    ) {
17174        if let Some(project) = self.project.as_ref() {
17175            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17176                return;
17177            };
17178
17179            if buffer.read(cx).file().is_none() {
17180                return;
17181            }
17182
17183            let focused = self.focus_handle(cx).contains_focused(window, cx);
17184
17185            let project = project.clone();
17186            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17187            self.blame_subscription =
17188                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17189            self.blame = Some(blame);
17190        }
17191    }
17192
17193    fn toggle_git_blame_inline_internal(
17194        &mut self,
17195        user_triggered: bool,
17196        window: &mut Window,
17197        cx: &mut Context<Self>,
17198    ) {
17199        if self.git_blame_inline_enabled {
17200            self.git_blame_inline_enabled = false;
17201            self.show_git_blame_inline = false;
17202            self.show_git_blame_inline_delay_task.take();
17203        } else {
17204            self.git_blame_inline_enabled = true;
17205            self.start_git_blame_inline(user_triggered, window, cx);
17206        }
17207
17208        cx.notify();
17209    }
17210
17211    fn start_git_blame_inline(
17212        &mut self,
17213        user_triggered: bool,
17214        window: &mut Window,
17215        cx: &mut Context<Self>,
17216    ) {
17217        self.start_git_blame(user_triggered, window, cx);
17218
17219        if ProjectSettings::get_global(cx)
17220            .git
17221            .inline_blame_delay()
17222            .is_some()
17223        {
17224            self.start_inline_blame_timer(window, cx);
17225        } else {
17226            self.show_git_blame_inline = true
17227        }
17228    }
17229
17230    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17231        self.blame.as_ref()
17232    }
17233
17234    pub fn show_git_blame_gutter(&self) -> bool {
17235        self.show_git_blame_gutter
17236    }
17237
17238    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17239        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17240    }
17241
17242    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17243        self.show_git_blame_inline
17244            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17245            && !self.newest_selection_head_on_empty_line(cx)
17246            && self.has_blame_entries(cx)
17247    }
17248
17249    fn has_blame_entries(&self, cx: &App) -> bool {
17250        self.blame()
17251            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17252    }
17253
17254    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17255        let cursor_anchor = self.selections.newest_anchor().head();
17256
17257        let snapshot = self.buffer.read(cx).snapshot(cx);
17258        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17259
17260        snapshot.line_len(buffer_row) == 0
17261    }
17262
17263    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17264        let buffer_and_selection = maybe!({
17265            let selection = self.selections.newest::<Point>(cx);
17266            let selection_range = selection.range();
17267
17268            let multi_buffer = self.buffer().read(cx);
17269            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17270            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17271
17272            let (buffer, range, _) = if selection.reversed {
17273                buffer_ranges.first()
17274            } else {
17275                buffer_ranges.last()
17276            }?;
17277
17278            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17279                ..text::ToPoint::to_point(&range.end, &buffer).row;
17280            Some((
17281                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
17282                selection,
17283            ))
17284        });
17285
17286        let Some((buffer, selection)) = buffer_and_selection else {
17287            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
17288        };
17289
17290        let Some(project) = self.project.as_ref() else {
17291            return Task::ready(Err(anyhow!("editor does not have project")));
17292        };
17293
17294        project.update(cx, |project, cx| {
17295            project.get_permalink_to_line(&buffer, selection, cx)
17296        })
17297    }
17298
17299    pub fn copy_permalink_to_line(
17300        &mut self,
17301        _: &CopyPermalinkToLine,
17302        window: &mut Window,
17303        cx: &mut Context<Self>,
17304    ) {
17305        let permalink_task = self.get_permalink_to_line(cx);
17306        let workspace = self.workspace();
17307
17308        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17309            Ok(permalink) => {
17310                cx.update(|_, cx| {
17311                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
17312                })
17313                .ok();
17314            }
17315            Err(err) => {
17316                let message = format!("Failed to copy permalink: {err}");
17317
17318                Err::<(), anyhow::Error>(err).log_err();
17319
17320                if let Some(workspace) = workspace {
17321                    workspace
17322                        .update_in(cx, |workspace, _, cx| {
17323                            struct CopyPermalinkToLine;
17324
17325                            workspace.show_toast(
17326                                Toast::new(
17327                                    NotificationId::unique::<CopyPermalinkToLine>(),
17328                                    message,
17329                                ),
17330                                cx,
17331                            )
17332                        })
17333                        .ok();
17334                }
17335            }
17336        })
17337        .detach();
17338    }
17339
17340    pub fn copy_file_location(
17341        &mut self,
17342        _: &CopyFileLocation,
17343        _: &mut Window,
17344        cx: &mut Context<Self>,
17345    ) {
17346        let selection = self.selections.newest::<Point>(cx).start.row + 1;
17347        if let Some(file) = self.target_file(cx) {
17348            if let Some(path) = file.path().to_str() {
17349                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
17350            }
17351        }
17352    }
17353
17354    pub fn open_permalink_to_line(
17355        &mut self,
17356        _: &OpenPermalinkToLine,
17357        window: &mut Window,
17358        cx: &mut Context<Self>,
17359    ) {
17360        let permalink_task = self.get_permalink_to_line(cx);
17361        let workspace = self.workspace();
17362
17363        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17364            Ok(permalink) => {
17365                cx.update(|_, cx| {
17366                    cx.open_url(permalink.as_ref());
17367                })
17368                .ok();
17369            }
17370            Err(err) => {
17371                let message = format!("Failed to open permalink: {err}");
17372
17373                Err::<(), anyhow::Error>(err).log_err();
17374
17375                if let Some(workspace) = workspace {
17376                    workspace
17377                        .update(cx, |workspace, cx| {
17378                            struct OpenPermalinkToLine;
17379
17380                            workspace.show_toast(
17381                                Toast::new(
17382                                    NotificationId::unique::<OpenPermalinkToLine>(),
17383                                    message,
17384                                ),
17385                                cx,
17386                            )
17387                        })
17388                        .ok();
17389                }
17390            }
17391        })
17392        .detach();
17393    }
17394
17395    pub fn insert_uuid_v4(
17396        &mut self,
17397        _: &InsertUuidV4,
17398        window: &mut Window,
17399        cx: &mut Context<Self>,
17400    ) {
17401        self.insert_uuid(UuidVersion::V4, window, cx);
17402    }
17403
17404    pub fn insert_uuid_v7(
17405        &mut self,
17406        _: &InsertUuidV7,
17407        window: &mut Window,
17408        cx: &mut Context<Self>,
17409    ) {
17410        self.insert_uuid(UuidVersion::V7, window, cx);
17411    }
17412
17413    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
17414        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17415        self.transact(window, cx, |this, window, cx| {
17416            let edits = this
17417                .selections
17418                .all::<Point>(cx)
17419                .into_iter()
17420                .map(|selection| {
17421                    let uuid = match version {
17422                        UuidVersion::V4 => uuid::Uuid::new_v4(),
17423                        UuidVersion::V7 => uuid::Uuid::now_v7(),
17424                    };
17425
17426                    (selection.range(), uuid.to_string())
17427                });
17428            this.edit(edits, cx);
17429            this.refresh_inline_completion(true, false, window, cx);
17430        });
17431    }
17432
17433    pub fn open_selections_in_multibuffer(
17434        &mut self,
17435        _: &OpenSelectionsInMultibuffer,
17436        window: &mut Window,
17437        cx: &mut Context<Self>,
17438    ) {
17439        let multibuffer = self.buffer.read(cx);
17440
17441        let Some(buffer) = multibuffer.as_singleton() else {
17442            return;
17443        };
17444
17445        let Some(workspace) = self.workspace() else {
17446            return;
17447        };
17448
17449        let locations = self
17450            .selections
17451            .disjoint_anchors()
17452            .iter()
17453            .map(|range| Location {
17454                buffer: buffer.clone(),
17455                range: range.start.text_anchor..range.end.text_anchor,
17456            })
17457            .collect::<Vec<_>>();
17458
17459        let title = multibuffer.title(cx).to_string();
17460
17461        cx.spawn_in(window, async move |_, cx| {
17462            workspace.update_in(cx, |workspace, window, cx| {
17463                Self::open_locations_in_multibuffer(
17464                    workspace,
17465                    locations,
17466                    format!("Selections for '{title}'"),
17467                    false,
17468                    MultibufferSelectionMode::All,
17469                    window,
17470                    cx,
17471                );
17472            })
17473        })
17474        .detach();
17475    }
17476
17477    /// Adds a row highlight for the given range. If a row has multiple highlights, the
17478    /// last highlight added will be used.
17479    ///
17480    /// If the range ends at the beginning of a line, then that line will not be highlighted.
17481    pub fn highlight_rows<T: 'static>(
17482        &mut self,
17483        range: Range<Anchor>,
17484        color: Hsla,
17485        options: RowHighlightOptions,
17486        cx: &mut Context<Self>,
17487    ) {
17488        let snapshot = self.buffer().read(cx).snapshot(cx);
17489        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17490        let ix = row_highlights.binary_search_by(|highlight| {
17491            Ordering::Equal
17492                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
17493                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
17494        });
17495
17496        if let Err(mut ix) = ix {
17497            let index = post_inc(&mut self.highlight_order);
17498
17499            // If this range intersects with the preceding highlight, then merge it with
17500            // the preceding highlight. Otherwise insert a new highlight.
17501            let mut merged = false;
17502            if ix > 0 {
17503                let prev_highlight = &mut row_highlights[ix - 1];
17504                if prev_highlight
17505                    .range
17506                    .end
17507                    .cmp(&range.start, &snapshot)
17508                    .is_ge()
17509                {
17510                    ix -= 1;
17511                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
17512                        prev_highlight.range.end = range.end;
17513                    }
17514                    merged = true;
17515                    prev_highlight.index = index;
17516                    prev_highlight.color = color;
17517                    prev_highlight.options = options;
17518                }
17519            }
17520
17521            if !merged {
17522                row_highlights.insert(
17523                    ix,
17524                    RowHighlight {
17525                        range: range.clone(),
17526                        index,
17527                        color,
17528                        options,
17529                        type_id: TypeId::of::<T>(),
17530                    },
17531                );
17532            }
17533
17534            // If any of the following highlights intersect with this one, merge them.
17535            while let Some(next_highlight) = row_highlights.get(ix + 1) {
17536                let highlight = &row_highlights[ix];
17537                if next_highlight
17538                    .range
17539                    .start
17540                    .cmp(&highlight.range.end, &snapshot)
17541                    .is_le()
17542                {
17543                    if next_highlight
17544                        .range
17545                        .end
17546                        .cmp(&highlight.range.end, &snapshot)
17547                        .is_gt()
17548                    {
17549                        row_highlights[ix].range.end = next_highlight.range.end;
17550                    }
17551                    row_highlights.remove(ix + 1);
17552                } else {
17553                    break;
17554                }
17555            }
17556        }
17557    }
17558
17559    /// Remove any highlighted row ranges of the given type that intersect the
17560    /// given ranges.
17561    pub fn remove_highlighted_rows<T: 'static>(
17562        &mut self,
17563        ranges_to_remove: Vec<Range<Anchor>>,
17564        cx: &mut Context<Self>,
17565    ) {
17566        let snapshot = self.buffer().read(cx).snapshot(cx);
17567        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17568        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
17569        row_highlights.retain(|highlight| {
17570            while let Some(range_to_remove) = ranges_to_remove.peek() {
17571                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
17572                    Ordering::Less | Ordering::Equal => {
17573                        ranges_to_remove.next();
17574                    }
17575                    Ordering::Greater => {
17576                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
17577                            Ordering::Less | Ordering::Equal => {
17578                                return false;
17579                            }
17580                            Ordering::Greater => break,
17581                        }
17582                    }
17583                }
17584            }
17585
17586            true
17587        })
17588    }
17589
17590    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
17591    pub fn clear_row_highlights<T: 'static>(&mut self) {
17592        self.highlighted_rows.remove(&TypeId::of::<T>());
17593    }
17594
17595    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
17596    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
17597        self.highlighted_rows
17598            .get(&TypeId::of::<T>())
17599            .map_or(&[] as &[_], |vec| vec.as_slice())
17600            .iter()
17601            .map(|highlight| (highlight.range.clone(), highlight.color))
17602    }
17603
17604    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
17605    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
17606    /// Allows to ignore certain kinds of highlights.
17607    pub fn highlighted_display_rows(
17608        &self,
17609        window: &mut Window,
17610        cx: &mut App,
17611    ) -> BTreeMap<DisplayRow, LineHighlight> {
17612        let snapshot = self.snapshot(window, cx);
17613        let mut used_highlight_orders = HashMap::default();
17614        self.highlighted_rows
17615            .iter()
17616            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
17617            .fold(
17618                BTreeMap::<DisplayRow, LineHighlight>::new(),
17619                |mut unique_rows, highlight| {
17620                    let start = highlight.range.start.to_display_point(&snapshot);
17621                    let end = highlight.range.end.to_display_point(&snapshot);
17622                    let start_row = start.row().0;
17623                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
17624                        && end.column() == 0
17625                    {
17626                        end.row().0.saturating_sub(1)
17627                    } else {
17628                        end.row().0
17629                    };
17630                    for row in start_row..=end_row {
17631                        let used_index =
17632                            used_highlight_orders.entry(row).or_insert(highlight.index);
17633                        if highlight.index >= *used_index {
17634                            *used_index = highlight.index;
17635                            unique_rows.insert(
17636                                DisplayRow(row),
17637                                LineHighlight {
17638                                    include_gutter: highlight.options.include_gutter,
17639                                    border: None,
17640                                    background: highlight.color.into(),
17641                                    type_id: Some(highlight.type_id),
17642                                },
17643                            );
17644                        }
17645                    }
17646                    unique_rows
17647                },
17648            )
17649    }
17650
17651    pub fn highlighted_display_row_for_autoscroll(
17652        &self,
17653        snapshot: &DisplaySnapshot,
17654    ) -> Option<DisplayRow> {
17655        self.highlighted_rows
17656            .values()
17657            .flat_map(|highlighted_rows| highlighted_rows.iter())
17658            .filter_map(|highlight| {
17659                if highlight.options.autoscroll {
17660                    Some(highlight.range.start.to_display_point(snapshot).row())
17661                } else {
17662                    None
17663                }
17664            })
17665            .min()
17666    }
17667
17668    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
17669        self.highlight_background::<SearchWithinRange>(
17670            ranges,
17671            |colors| colors.editor_document_highlight_read_background,
17672            cx,
17673        )
17674    }
17675
17676    pub fn set_breadcrumb_header(&mut self, new_header: String) {
17677        self.breadcrumb_header = Some(new_header);
17678    }
17679
17680    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
17681        self.clear_background_highlights::<SearchWithinRange>(cx);
17682    }
17683
17684    pub fn highlight_background<T: 'static>(
17685        &mut self,
17686        ranges: &[Range<Anchor>],
17687        color_fetcher: fn(&ThemeColors) -> Hsla,
17688        cx: &mut Context<Self>,
17689    ) {
17690        self.background_highlights
17691            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17692        self.scrollbar_marker_state.dirty = true;
17693        cx.notify();
17694    }
17695
17696    pub fn clear_background_highlights<T: 'static>(
17697        &mut self,
17698        cx: &mut Context<Self>,
17699    ) -> Option<BackgroundHighlight> {
17700        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
17701        if !text_highlights.1.is_empty() {
17702            self.scrollbar_marker_state.dirty = true;
17703            cx.notify();
17704        }
17705        Some(text_highlights)
17706    }
17707
17708    pub fn highlight_gutter<T: 'static>(
17709        &mut self,
17710        ranges: &[Range<Anchor>],
17711        color_fetcher: fn(&App) -> Hsla,
17712        cx: &mut Context<Self>,
17713    ) {
17714        self.gutter_highlights
17715            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17716        cx.notify();
17717    }
17718
17719    pub fn clear_gutter_highlights<T: 'static>(
17720        &mut self,
17721        cx: &mut Context<Self>,
17722    ) -> Option<GutterHighlight> {
17723        cx.notify();
17724        self.gutter_highlights.remove(&TypeId::of::<T>())
17725    }
17726
17727    #[cfg(feature = "test-support")]
17728    pub fn all_text_background_highlights(
17729        &self,
17730        window: &mut Window,
17731        cx: &mut Context<Self>,
17732    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17733        let snapshot = self.snapshot(window, cx);
17734        let buffer = &snapshot.buffer_snapshot;
17735        let start = buffer.anchor_before(0);
17736        let end = buffer.anchor_after(buffer.len());
17737        let theme = cx.theme().colors();
17738        self.background_highlights_in_range(start..end, &snapshot, theme)
17739    }
17740
17741    #[cfg(feature = "test-support")]
17742    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
17743        let snapshot = self.buffer().read(cx).snapshot(cx);
17744
17745        let highlights = self
17746            .background_highlights
17747            .get(&TypeId::of::<items::BufferSearchHighlights>());
17748
17749        if let Some((_color, ranges)) = highlights {
17750            ranges
17751                .iter()
17752                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
17753                .collect_vec()
17754        } else {
17755            vec![]
17756        }
17757    }
17758
17759    fn document_highlights_for_position<'a>(
17760        &'a self,
17761        position: Anchor,
17762        buffer: &'a MultiBufferSnapshot,
17763    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
17764        let read_highlights = self
17765            .background_highlights
17766            .get(&TypeId::of::<DocumentHighlightRead>())
17767            .map(|h| &h.1);
17768        let write_highlights = self
17769            .background_highlights
17770            .get(&TypeId::of::<DocumentHighlightWrite>())
17771            .map(|h| &h.1);
17772        let left_position = position.bias_left(buffer);
17773        let right_position = position.bias_right(buffer);
17774        read_highlights
17775            .into_iter()
17776            .chain(write_highlights)
17777            .flat_map(move |ranges| {
17778                let start_ix = match ranges.binary_search_by(|probe| {
17779                    let cmp = probe.end.cmp(&left_position, buffer);
17780                    if cmp.is_ge() {
17781                        Ordering::Greater
17782                    } else {
17783                        Ordering::Less
17784                    }
17785                }) {
17786                    Ok(i) | Err(i) => i,
17787                };
17788
17789                ranges[start_ix..]
17790                    .iter()
17791                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
17792            })
17793    }
17794
17795    pub fn has_background_highlights<T: 'static>(&self) -> bool {
17796        self.background_highlights
17797            .get(&TypeId::of::<T>())
17798            .map_or(false, |(_, highlights)| !highlights.is_empty())
17799    }
17800
17801    pub fn background_highlights_in_range(
17802        &self,
17803        search_range: Range<Anchor>,
17804        display_snapshot: &DisplaySnapshot,
17805        theme: &ThemeColors,
17806    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17807        let mut results = Vec::new();
17808        for (color_fetcher, ranges) in self.background_highlights.values() {
17809            let color = color_fetcher(theme);
17810            let start_ix = match ranges.binary_search_by(|probe| {
17811                let cmp = probe
17812                    .end
17813                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17814                if cmp.is_gt() {
17815                    Ordering::Greater
17816                } else {
17817                    Ordering::Less
17818                }
17819            }) {
17820                Ok(i) | Err(i) => i,
17821            };
17822            for range in &ranges[start_ix..] {
17823                if range
17824                    .start
17825                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17826                    .is_ge()
17827                {
17828                    break;
17829                }
17830
17831                let start = range.start.to_display_point(display_snapshot);
17832                let end = range.end.to_display_point(display_snapshot);
17833                results.push((start..end, color))
17834            }
17835        }
17836        results
17837    }
17838
17839    pub fn background_highlight_row_ranges<T: 'static>(
17840        &self,
17841        search_range: Range<Anchor>,
17842        display_snapshot: &DisplaySnapshot,
17843        count: usize,
17844    ) -> Vec<RangeInclusive<DisplayPoint>> {
17845        let mut results = Vec::new();
17846        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
17847            return vec![];
17848        };
17849
17850        let start_ix = match ranges.binary_search_by(|probe| {
17851            let cmp = probe
17852                .end
17853                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17854            if cmp.is_gt() {
17855                Ordering::Greater
17856            } else {
17857                Ordering::Less
17858            }
17859        }) {
17860            Ok(i) | Err(i) => i,
17861        };
17862        let mut push_region = |start: Option<Point>, end: Option<Point>| {
17863            if let (Some(start_display), Some(end_display)) = (start, end) {
17864                results.push(
17865                    start_display.to_display_point(display_snapshot)
17866                        ..=end_display.to_display_point(display_snapshot),
17867                );
17868            }
17869        };
17870        let mut start_row: Option<Point> = None;
17871        let mut end_row: Option<Point> = None;
17872        if ranges.len() > count {
17873            return Vec::new();
17874        }
17875        for range in &ranges[start_ix..] {
17876            if range
17877                .start
17878                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17879                .is_ge()
17880            {
17881                break;
17882            }
17883            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
17884            if let Some(current_row) = &end_row {
17885                if end.row == current_row.row {
17886                    continue;
17887                }
17888            }
17889            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
17890            if start_row.is_none() {
17891                assert_eq!(end_row, None);
17892                start_row = Some(start);
17893                end_row = Some(end);
17894                continue;
17895            }
17896            if let Some(current_end) = end_row.as_mut() {
17897                if start.row > current_end.row + 1 {
17898                    push_region(start_row, end_row);
17899                    start_row = Some(start);
17900                    end_row = Some(end);
17901                } else {
17902                    // Merge two hunks.
17903                    *current_end = end;
17904                }
17905            } else {
17906                unreachable!();
17907            }
17908        }
17909        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
17910        push_region(start_row, end_row);
17911        results
17912    }
17913
17914    pub fn gutter_highlights_in_range(
17915        &self,
17916        search_range: Range<Anchor>,
17917        display_snapshot: &DisplaySnapshot,
17918        cx: &App,
17919    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17920        let mut results = Vec::new();
17921        for (color_fetcher, ranges) in self.gutter_highlights.values() {
17922            let color = color_fetcher(cx);
17923            let start_ix = match ranges.binary_search_by(|probe| {
17924                let cmp = probe
17925                    .end
17926                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17927                if cmp.is_gt() {
17928                    Ordering::Greater
17929                } else {
17930                    Ordering::Less
17931                }
17932            }) {
17933                Ok(i) | Err(i) => i,
17934            };
17935            for range in &ranges[start_ix..] {
17936                if range
17937                    .start
17938                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17939                    .is_ge()
17940                {
17941                    break;
17942                }
17943
17944                let start = range.start.to_display_point(display_snapshot);
17945                let end = range.end.to_display_point(display_snapshot);
17946                results.push((start..end, color))
17947            }
17948        }
17949        results
17950    }
17951
17952    /// Get the text ranges corresponding to the redaction query
17953    pub fn redacted_ranges(
17954        &self,
17955        search_range: Range<Anchor>,
17956        display_snapshot: &DisplaySnapshot,
17957        cx: &App,
17958    ) -> Vec<Range<DisplayPoint>> {
17959        display_snapshot
17960            .buffer_snapshot
17961            .redacted_ranges(search_range, |file| {
17962                if let Some(file) = file {
17963                    file.is_private()
17964                        && EditorSettings::get(
17965                            Some(SettingsLocation {
17966                                worktree_id: file.worktree_id(cx),
17967                                path: file.path().as_ref(),
17968                            }),
17969                            cx,
17970                        )
17971                        .redact_private_values
17972                } else {
17973                    false
17974                }
17975            })
17976            .map(|range| {
17977                range.start.to_display_point(display_snapshot)
17978                    ..range.end.to_display_point(display_snapshot)
17979            })
17980            .collect()
17981    }
17982
17983    pub fn highlight_text<T: 'static>(
17984        &mut self,
17985        ranges: Vec<Range<Anchor>>,
17986        style: HighlightStyle,
17987        cx: &mut Context<Self>,
17988    ) {
17989        self.display_map.update(cx, |map, _| {
17990            map.highlight_text(TypeId::of::<T>(), ranges, style)
17991        });
17992        cx.notify();
17993    }
17994
17995    pub(crate) fn highlight_inlays<T: 'static>(
17996        &mut self,
17997        highlights: Vec<InlayHighlight>,
17998        style: HighlightStyle,
17999        cx: &mut Context<Self>,
18000    ) {
18001        self.display_map.update(cx, |map, _| {
18002            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18003        });
18004        cx.notify();
18005    }
18006
18007    pub fn text_highlights<'a, T: 'static>(
18008        &'a self,
18009        cx: &'a App,
18010    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18011        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18012    }
18013
18014    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18015        let cleared = self
18016            .display_map
18017            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18018        if cleared {
18019            cx.notify();
18020        }
18021    }
18022
18023    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18024        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18025            && self.focus_handle.is_focused(window)
18026    }
18027
18028    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18029        self.show_cursor_when_unfocused = is_enabled;
18030        cx.notify();
18031    }
18032
18033    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18034        cx.notify();
18035    }
18036
18037    fn on_debug_session_event(
18038        &mut self,
18039        _session: Entity<Session>,
18040        event: &SessionEvent,
18041        cx: &mut Context<Self>,
18042    ) {
18043        match event {
18044            SessionEvent::InvalidateInlineValue => {
18045                self.refresh_inline_values(cx);
18046            }
18047            _ => {}
18048        }
18049    }
18050
18051    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18052        let Some(project) = self.project.clone() else {
18053            return;
18054        };
18055
18056        if !self.inline_value_cache.enabled {
18057            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18058            self.splice_inlays(&inlays, Vec::new(), cx);
18059            return;
18060        }
18061
18062        let current_execution_position = self
18063            .highlighted_rows
18064            .get(&TypeId::of::<ActiveDebugLine>())
18065            .and_then(|lines| lines.last().map(|line| line.range.start));
18066
18067        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18068            let snapshot = editor
18069                .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18070                .ok()?;
18071
18072            let inline_values = editor
18073                .update(cx, |editor, cx| {
18074                    let Some(current_execution_position) = current_execution_position else {
18075                        return Some(Task::ready(Ok(Vec::new())));
18076                    };
18077
18078                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18079                        let snapshot = buffer.snapshot(cx);
18080
18081                        let excerpt = snapshot.excerpt_containing(
18082                            current_execution_position..current_execution_position,
18083                        )?;
18084
18085                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18086                    })?;
18087
18088                    let range =
18089                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18090
18091                    project.inline_values(buffer, range, cx)
18092                })
18093                .ok()
18094                .flatten()?
18095                .await
18096                .context("refreshing debugger inlays")
18097                .log_err()?;
18098
18099            let (excerpt_id, buffer_id) = snapshot
18100                .excerpts()
18101                .next()
18102                .map(|excerpt| (excerpt.0, excerpt.1.remote_id()))?;
18103            editor
18104                .update(cx, |editor, cx| {
18105                    let new_inlays = inline_values
18106                        .into_iter()
18107                        .map(|debugger_value| {
18108                            Inlay::debugger_hint(
18109                                post_inc(&mut editor.next_inlay_id),
18110                                Anchor::in_buffer(excerpt_id, buffer_id, debugger_value.position),
18111                                debugger_value.text(),
18112                            )
18113                        })
18114                        .collect::<Vec<_>>();
18115                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18116                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18117
18118                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18119                })
18120                .ok()?;
18121            Some(())
18122        });
18123    }
18124
18125    fn on_buffer_event(
18126        &mut self,
18127        multibuffer: &Entity<MultiBuffer>,
18128        event: &multi_buffer::Event,
18129        window: &mut Window,
18130        cx: &mut Context<Self>,
18131    ) {
18132        match event {
18133            multi_buffer::Event::Edited {
18134                singleton_buffer_edited,
18135                edited_buffer: buffer_edited,
18136            } => {
18137                self.scrollbar_marker_state.dirty = true;
18138                self.active_indent_guides_state.dirty = true;
18139                self.refresh_active_diagnostics(cx);
18140                self.refresh_code_actions(window, cx);
18141                self.refresh_selected_text_highlights(true, window, cx);
18142                refresh_matching_bracket_highlights(self, window, cx);
18143                if self.has_active_inline_completion() {
18144                    self.update_visible_inline_completion(window, cx);
18145                }
18146                if let Some(buffer) = buffer_edited {
18147                    let buffer_id = buffer.read(cx).remote_id();
18148                    if !self.registered_buffers.contains_key(&buffer_id) {
18149                        if let Some(project) = self.project.as_ref() {
18150                            project.update(cx, |project, cx| {
18151                                self.registered_buffers.insert(
18152                                    buffer_id,
18153                                    project.register_buffer_with_language_servers(&buffer, cx),
18154                                );
18155                            })
18156                        }
18157                    }
18158                }
18159                cx.emit(EditorEvent::BufferEdited);
18160                cx.emit(SearchEvent::MatchesInvalidated);
18161                if *singleton_buffer_edited {
18162                    if let Some(project) = &self.project {
18163                        #[allow(clippy::mutable_key_type)]
18164                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18165                            multibuffer
18166                                .all_buffers()
18167                                .into_iter()
18168                                .filter_map(|buffer| {
18169                                    buffer.update(cx, |buffer, cx| {
18170                                        let language = buffer.language()?;
18171                                        let should_discard = project.update(cx, |project, cx| {
18172                                            project.is_local()
18173                                                && !project.has_language_servers_for(buffer, cx)
18174                                        });
18175                                        should_discard.not().then_some(language.clone())
18176                                    })
18177                                })
18178                                .collect::<HashSet<_>>()
18179                        });
18180                        if !languages_affected.is_empty() {
18181                            self.refresh_inlay_hints(
18182                                InlayHintRefreshReason::BufferEdited(languages_affected),
18183                                cx,
18184                            );
18185                        }
18186                    }
18187                }
18188
18189                let Some(project) = &self.project else { return };
18190                let (telemetry, is_via_ssh) = {
18191                    let project = project.read(cx);
18192                    let telemetry = project.client().telemetry().clone();
18193                    let is_via_ssh = project.is_via_ssh();
18194                    (telemetry, is_via_ssh)
18195                };
18196                refresh_linked_ranges(self, window, cx);
18197                telemetry.log_edit_event("editor", is_via_ssh);
18198            }
18199            multi_buffer::Event::ExcerptsAdded {
18200                buffer,
18201                predecessor,
18202                excerpts,
18203            } => {
18204                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18205                let buffer_id = buffer.read(cx).remote_id();
18206                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
18207                    if let Some(project) = &self.project {
18208                        update_uncommitted_diff_for_buffer(
18209                            cx.entity(),
18210                            project,
18211                            [buffer.clone()],
18212                            self.buffer.clone(),
18213                            cx,
18214                        )
18215                        .detach();
18216                    }
18217                }
18218                cx.emit(EditorEvent::ExcerptsAdded {
18219                    buffer: buffer.clone(),
18220                    predecessor: *predecessor,
18221                    excerpts: excerpts.clone(),
18222                });
18223                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18224            }
18225            multi_buffer::Event::ExcerptsRemoved {
18226                ids,
18227                removed_buffer_ids,
18228            } => {
18229                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
18230                let buffer = self.buffer.read(cx);
18231                self.registered_buffers
18232                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
18233                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18234                cx.emit(EditorEvent::ExcerptsRemoved {
18235                    ids: ids.clone(),
18236                    removed_buffer_ids: removed_buffer_ids.clone(),
18237                })
18238            }
18239            multi_buffer::Event::ExcerptsEdited {
18240                excerpt_ids,
18241                buffer_ids,
18242            } => {
18243                self.display_map.update(cx, |map, cx| {
18244                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
18245                });
18246                cx.emit(EditorEvent::ExcerptsEdited {
18247                    ids: excerpt_ids.clone(),
18248                })
18249            }
18250            multi_buffer::Event::ExcerptsExpanded { ids } => {
18251                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18252                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
18253            }
18254            multi_buffer::Event::Reparsed(buffer_id) => {
18255                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18256                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18257
18258                cx.emit(EditorEvent::Reparsed(*buffer_id));
18259            }
18260            multi_buffer::Event::DiffHunksToggled => {
18261                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18262            }
18263            multi_buffer::Event::LanguageChanged(buffer_id) => {
18264                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
18265                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18266                cx.emit(EditorEvent::Reparsed(*buffer_id));
18267                cx.notify();
18268            }
18269            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
18270            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
18271            multi_buffer::Event::FileHandleChanged
18272            | multi_buffer::Event::Reloaded
18273            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
18274            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
18275            multi_buffer::Event::DiagnosticsUpdated => {
18276                self.refresh_active_diagnostics(cx);
18277                self.refresh_inline_diagnostics(true, window, cx);
18278                self.scrollbar_marker_state.dirty = true;
18279                cx.notify();
18280            }
18281            _ => {}
18282        };
18283    }
18284
18285    pub fn start_temporary_diff_override(&mut self) {
18286        self.load_diff_task.take();
18287        self.temporary_diff_override = true;
18288    }
18289
18290    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
18291        self.temporary_diff_override = false;
18292        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
18293        self.buffer.update(cx, |buffer, cx| {
18294            buffer.set_all_diff_hunks_collapsed(cx);
18295        });
18296
18297        if let Some(project) = self.project.clone() {
18298            self.load_diff_task = Some(
18299                update_uncommitted_diff_for_buffer(
18300                    cx.entity(),
18301                    &project,
18302                    self.buffer.read(cx).all_buffers(),
18303                    self.buffer.clone(),
18304                    cx,
18305                )
18306                .shared(),
18307            );
18308        }
18309    }
18310
18311    fn on_display_map_changed(
18312        &mut self,
18313        _: Entity<DisplayMap>,
18314        _: &mut Window,
18315        cx: &mut Context<Self>,
18316    ) {
18317        cx.notify();
18318    }
18319
18320    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18321        let new_severity = if self.diagnostics_enabled() {
18322            EditorSettings::get_global(cx)
18323                .diagnostics_max_severity
18324                .unwrap_or(DiagnosticSeverity::Hint)
18325        } else {
18326            DiagnosticSeverity::Off
18327        };
18328        self.set_max_diagnostics_severity(new_severity, cx);
18329        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18330        self.update_edit_prediction_settings(cx);
18331        self.refresh_inline_completion(true, false, window, cx);
18332        self.refresh_inlay_hints(
18333            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
18334                self.selections.newest_anchor().head(),
18335                &self.buffer.read(cx).snapshot(cx),
18336                cx,
18337            )),
18338            cx,
18339        );
18340
18341        let old_cursor_shape = self.cursor_shape;
18342
18343        {
18344            let editor_settings = EditorSettings::get_global(cx);
18345            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
18346            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
18347            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
18348            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
18349        }
18350
18351        if old_cursor_shape != self.cursor_shape {
18352            cx.emit(EditorEvent::CursorShapeChanged);
18353        }
18354
18355        let project_settings = ProjectSettings::get_global(cx);
18356        self.serialize_dirty_buffers =
18357            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
18358
18359        if self.mode.is_full() {
18360            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
18361            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
18362            if self.show_inline_diagnostics != show_inline_diagnostics {
18363                self.show_inline_diagnostics = show_inline_diagnostics;
18364                self.refresh_inline_diagnostics(false, window, cx);
18365            }
18366
18367            if self.git_blame_inline_enabled != inline_blame_enabled {
18368                self.toggle_git_blame_inline_internal(false, window, cx);
18369            }
18370
18371            let minimap_settings = EditorSettings::get_global(cx).minimap;
18372            if self.minimap_visibility.visible() != minimap_settings.minimap_enabled() {
18373                self.set_minimap_visibility(
18374                    self.minimap_visibility.toggle_visibility(),
18375                    window,
18376                    cx,
18377                );
18378            } else if let Some(minimap_entity) = self.minimap.as_ref() {
18379                minimap_entity.update(cx, |minimap_editor, cx| {
18380                    minimap_editor.update_minimap_configuration(minimap_settings, cx)
18381                })
18382            }
18383        }
18384
18385        cx.notify();
18386    }
18387
18388    pub fn set_searchable(&mut self, searchable: bool) {
18389        self.searchable = searchable;
18390    }
18391
18392    pub fn searchable(&self) -> bool {
18393        self.searchable
18394    }
18395
18396    fn open_proposed_changes_editor(
18397        &mut self,
18398        _: &OpenProposedChangesEditor,
18399        window: &mut Window,
18400        cx: &mut Context<Self>,
18401    ) {
18402        let Some(workspace) = self.workspace() else {
18403            cx.propagate();
18404            return;
18405        };
18406
18407        let selections = self.selections.all::<usize>(cx);
18408        let multi_buffer = self.buffer.read(cx);
18409        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18410        let mut new_selections_by_buffer = HashMap::default();
18411        for selection in selections {
18412            for (buffer, range, _) in
18413                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
18414            {
18415                let mut range = range.to_point(buffer);
18416                range.start.column = 0;
18417                range.end.column = buffer.line_len(range.end.row);
18418                new_selections_by_buffer
18419                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
18420                    .or_insert(Vec::new())
18421                    .push(range)
18422            }
18423        }
18424
18425        let proposed_changes_buffers = new_selections_by_buffer
18426            .into_iter()
18427            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
18428            .collect::<Vec<_>>();
18429        let proposed_changes_editor = cx.new(|cx| {
18430            ProposedChangesEditor::new(
18431                "Proposed changes",
18432                proposed_changes_buffers,
18433                self.project.clone(),
18434                window,
18435                cx,
18436            )
18437        });
18438
18439        window.defer(cx, move |window, cx| {
18440            workspace.update(cx, |workspace, cx| {
18441                workspace.active_pane().update(cx, |pane, cx| {
18442                    pane.add_item(
18443                        Box::new(proposed_changes_editor),
18444                        true,
18445                        true,
18446                        None,
18447                        window,
18448                        cx,
18449                    );
18450                });
18451            });
18452        });
18453    }
18454
18455    pub fn open_excerpts_in_split(
18456        &mut self,
18457        _: &OpenExcerptsSplit,
18458        window: &mut Window,
18459        cx: &mut Context<Self>,
18460    ) {
18461        self.open_excerpts_common(None, true, window, cx)
18462    }
18463
18464    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
18465        self.open_excerpts_common(None, false, window, cx)
18466    }
18467
18468    fn open_excerpts_common(
18469        &mut self,
18470        jump_data: Option<JumpData>,
18471        split: bool,
18472        window: &mut Window,
18473        cx: &mut Context<Self>,
18474    ) {
18475        let Some(workspace) = self.workspace() else {
18476            cx.propagate();
18477            return;
18478        };
18479
18480        if self.buffer.read(cx).is_singleton() {
18481            cx.propagate();
18482            return;
18483        }
18484
18485        let mut new_selections_by_buffer = HashMap::default();
18486        match &jump_data {
18487            Some(JumpData::MultiBufferPoint {
18488                excerpt_id,
18489                position,
18490                anchor,
18491                line_offset_from_top,
18492            }) => {
18493                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18494                if let Some(buffer) = multi_buffer_snapshot
18495                    .buffer_id_for_excerpt(*excerpt_id)
18496                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
18497                {
18498                    let buffer_snapshot = buffer.read(cx).snapshot();
18499                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
18500                        language::ToPoint::to_point(anchor, &buffer_snapshot)
18501                    } else {
18502                        buffer_snapshot.clip_point(*position, Bias::Left)
18503                    };
18504                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
18505                    new_selections_by_buffer.insert(
18506                        buffer,
18507                        (
18508                            vec![jump_to_offset..jump_to_offset],
18509                            Some(*line_offset_from_top),
18510                        ),
18511                    );
18512                }
18513            }
18514            Some(JumpData::MultiBufferRow {
18515                row,
18516                line_offset_from_top,
18517            }) => {
18518                let point = MultiBufferPoint::new(row.0, 0);
18519                if let Some((buffer, buffer_point, _)) =
18520                    self.buffer.read(cx).point_to_buffer_point(point, cx)
18521                {
18522                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
18523                    new_selections_by_buffer
18524                        .entry(buffer)
18525                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
18526                        .0
18527                        .push(buffer_offset..buffer_offset)
18528                }
18529            }
18530            None => {
18531                let selections = self.selections.all::<usize>(cx);
18532                let multi_buffer = self.buffer.read(cx);
18533                for selection in selections {
18534                    for (snapshot, range, _, anchor) in multi_buffer
18535                        .snapshot(cx)
18536                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
18537                    {
18538                        if let Some(anchor) = anchor {
18539                            // selection is in a deleted hunk
18540                            let Some(buffer_id) = anchor.buffer_id else {
18541                                continue;
18542                            };
18543                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
18544                                continue;
18545                            };
18546                            let offset = text::ToOffset::to_offset(
18547                                &anchor.text_anchor,
18548                                &buffer_handle.read(cx).snapshot(),
18549                            );
18550                            let range = offset..offset;
18551                            new_selections_by_buffer
18552                                .entry(buffer_handle)
18553                                .or_insert((Vec::new(), None))
18554                                .0
18555                                .push(range)
18556                        } else {
18557                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
18558                            else {
18559                                continue;
18560                            };
18561                            new_selections_by_buffer
18562                                .entry(buffer_handle)
18563                                .or_insert((Vec::new(), None))
18564                                .0
18565                                .push(range)
18566                        }
18567                    }
18568                }
18569            }
18570        }
18571
18572        new_selections_by_buffer
18573            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
18574
18575        if new_selections_by_buffer.is_empty() {
18576            return;
18577        }
18578
18579        // We defer the pane interaction because we ourselves are a workspace item
18580        // and activating a new item causes the pane to call a method on us reentrantly,
18581        // which panics if we're on the stack.
18582        window.defer(cx, move |window, cx| {
18583            workspace.update(cx, |workspace, cx| {
18584                let pane = if split {
18585                    workspace.adjacent_pane(window, cx)
18586                } else {
18587                    workspace.active_pane().clone()
18588                };
18589
18590                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
18591                    let editor = buffer
18592                        .read(cx)
18593                        .file()
18594                        .is_none()
18595                        .then(|| {
18596                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
18597                            // so `workspace.open_project_item` will never find them, always opening a new editor.
18598                            // Instead, we try to activate the existing editor in the pane first.
18599                            let (editor, pane_item_index) =
18600                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
18601                                    let editor = item.downcast::<Editor>()?;
18602                                    let singleton_buffer =
18603                                        editor.read(cx).buffer().read(cx).as_singleton()?;
18604                                    if singleton_buffer == buffer {
18605                                        Some((editor, i))
18606                                    } else {
18607                                        None
18608                                    }
18609                                })?;
18610                            pane.update(cx, |pane, cx| {
18611                                pane.activate_item(pane_item_index, true, true, window, cx)
18612                            });
18613                            Some(editor)
18614                        })
18615                        .flatten()
18616                        .unwrap_or_else(|| {
18617                            workspace.open_project_item::<Self>(
18618                                pane.clone(),
18619                                buffer,
18620                                true,
18621                                true,
18622                                window,
18623                                cx,
18624                            )
18625                        });
18626
18627                    editor.update(cx, |editor, cx| {
18628                        let autoscroll = match scroll_offset {
18629                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
18630                            None => Autoscroll::newest(),
18631                        };
18632                        let nav_history = editor.nav_history.take();
18633                        editor.change_selections(Some(autoscroll), window, cx, |s| {
18634                            s.select_ranges(ranges);
18635                        });
18636                        editor.nav_history = nav_history;
18637                    });
18638                }
18639            })
18640        });
18641    }
18642
18643    // For now, don't allow opening excerpts in buffers that aren't backed by
18644    // regular project files.
18645    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
18646        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
18647    }
18648
18649    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
18650        let snapshot = self.buffer.read(cx).read(cx);
18651        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
18652        Some(
18653            ranges
18654                .iter()
18655                .map(move |range| {
18656                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
18657                })
18658                .collect(),
18659        )
18660    }
18661
18662    fn selection_replacement_ranges(
18663        &self,
18664        range: Range<OffsetUtf16>,
18665        cx: &mut App,
18666    ) -> Vec<Range<OffsetUtf16>> {
18667        let selections = self.selections.all::<OffsetUtf16>(cx);
18668        let newest_selection = selections
18669            .iter()
18670            .max_by_key(|selection| selection.id)
18671            .unwrap();
18672        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
18673        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
18674        let snapshot = self.buffer.read(cx).read(cx);
18675        selections
18676            .into_iter()
18677            .map(|mut selection| {
18678                selection.start.0 =
18679                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
18680                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
18681                snapshot.clip_offset_utf16(selection.start, Bias::Left)
18682                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
18683            })
18684            .collect()
18685    }
18686
18687    fn report_editor_event(
18688        &self,
18689        event_type: &'static str,
18690        file_extension: Option<String>,
18691        cx: &App,
18692    ) {
18693        if cfg!(any(test, feature = "test-support")) {
18694            return;
18695        }
18696
18697        let Some(project) = &self.project else { return };
18698
18699        // If None, we are in a file without an extension
18700        let file = self
18701            .buffer
18702            .read(cx)
18703            .as_singleton()
18704            .and_then(|b| b.read(cx).file());
18705        let file_extension = file_extension.or(file
18706            .as_ref()
18707            .and_then(|file| Path::new(file.file_name(cx)).extension())
18708            .and_then(|e| e.to_str())
18709            .map(|a| a.to_string()));
18710
18711        let vim_mode = vim_enabled(cx);
18712
18713        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
18714        let copilot_enabled = edit_predictions_provider
18715            == language::language_settings::EditPredictionProvider::Copilot;
18716        let copilot_enabled_for_language = self
18717            .buffer
18718            .read(cx)
18719            .language_settings(cx)
18720            .show_edit_predictions;
18721
18722        let project = project.read(cx);
18723        telemetry::event!(
18724            event_type,
18725            file_extension,
18726            vim_mode,
18727            copilot_enabled,
18728            copilot_enabled_for_language,
18729            edit_predictions_provider,
18730            is_via_ssh = project.is_via_ssh(),
18731        );
18732    }
18733
18734    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
18735    /// with each line being an array of {text, highlight} objects.
18736    fn copy_highlight_json(
18737        &mut self,
18738        _: &CopyHighlightJson,
18739        window: &mut Window,
18740        cx: &mut Context<Self>,
18741    ) {
18742        #[derive(Serialize)]
18743        struct Chunk<'a> {
18744            text: String,
18745            highlight: Option<&'a str>,
18746        }
18747
18748        let snapshot = self.buffer.read(cx).snapshot(cx);
18749        let range = self
18750            .selected_text_range(false, window, cx)
18751            .and_then(|selection| {
18752                if selection.range.is_empty() {
18753                    None
18754                } else {
18755                    Some(selection.range)
18756                }
18757            })
18758            .unwrap_or_else(|| 0..snapshot.len());
18759
18760        let chunks = snapshot.chunks(range, true);
18761        let mut lines = Vec::new();
18762        let mut line: VecDeque<Chunk> = VecDeque::new();
18763
18764        let Some(style) = self.style.as_ref() else {
18765            return;
18766        };
18767
18768        for chunk in chunks {
18769            let highlight = chunk
18770                .syntax_highlight_id
18771                .and_then(|id| id.name(&style.syntax));
18772            let mut chunk_lines = chunk.text.split('\n').peekable();
18773            while let Some(text) = chunk_lines.next() {
18774                let mut merged_with_last_token = false;
18775                if let Some(last_token) = line.back_mut() {
18776                    if last_token.highlight == highlight {
18777                        last_token.text.push_str(text);
18778                        merged_with_last_token = true;
18779                    }
18780                }
18781
18782                if !merged_with_last_token {
18783                    line.push_back(Chunk {
18784                        text: text.into(),
18785                        highlight,
18786                    });
18787                }
18788
18789                if chunk_lines.peek().is_some() {
18790                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
18791                        line.pop_front();
18792                    }
18793                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
18794                        line.pop_back();
18795                    }
18796
18797                    lines.push(mem::take(&mut line));
18798                }
18799            }
18800        }
18801
18802        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
18803            return;
18804        };
18805        cx.write_to_clipboard(ClipboardItem::new_string(lines));
18806    }
18807
18808    pub fn open_context_menu(
18809        &mut self,
18810        _: &OpenContextMenu,
18811        window: &mut Window,
18812        cx: &mut Context<Self>,
18813    ) {
18814        self.request_autoscroll(Autoscroll::newest(), cx);
18815        let position = self.selections.newest_display(cx).start;
18816        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
18817    }
18818
18819    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
18820        &self.inlay_hint_cache
18821    }
18822
18823    pub fn replay_insert_event(
18824        &mut self,
18825        text: &str,
18826        relative_utf16_range: Option<Range<isize>>,
18827        window: &mut Window,
18828        cx: &mut Context<Self>,
18829    ) {
18830        if !self.input_enabled {
18831            cx.emit(EditorEvent::InputIgnored { text: text.into() });
18832            return;
18833        }
18834        if let Some(relative_utf16_range) = relative_utf16_range {
18835            let selections = self.selections.all::<OffsetUtf16>(cx);
18836            self.change_selections(None, window, cx, |s| {
18837                let new_ranges = selections.into_iter().map(|range| {
18838                    let start = OffsetUtf16(
18839                        range
18840                            .head()
18841                            .0
18842                            .saturating_add_signed(relative_utf16_range.start),
18843                    );
18844                    let end = OffsetUtf16(
18845                        range
18846                            .head()
18847                            .0
18848                            .saturating_add_signed(relative_utf16_range.end),
18849                    );
18850                    start..end
18851                });
18852                s.select_ranges(new_ranges);
18853            });
18854        }
18855
18856        self.handle_input(text, window, cx);
18857    }
18858
18859    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
18860        let Some(provider) = self.semantics_provider.as_ref() else {
18861            return false;
18862        };
18863
18864        let mut supports = false;
18865        self.buffer().update(cx, |this, cx| {
18866            this.for_each_buffer(|buffer| {
18867                supports |= provider.supports_inlay_hints(buffer, cx);
18868            });
18869        });
18870
18871        supports
18872    }
18873
18874    pub fn is_focused(&self, window: &Window) -> bool {
18875        self.focus_handle.is_focused(window)
18876    }
18877
18878    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18879        cx.emit(EditorEvent::Focused);
18880
18881        if let Some(descendant) = self
18882            .last_focused_descendant
18883            .take()
18884            .and_then(|descendant| descendant.upgrade())
18885        {
18886            window.focus(&descendant);
18887        } else {
18888            if let Some(blame) = self.blame.as_ref() {
18889                blame.update(cx, GitBlame::focus)
18890            }
18891
18892            self.blink_manager.update(cx, BlinkManager::enable);
18893            self.show_cursor_names(window, cx);
18894            self.buffer.update(cx, |buffer, cx| {
18895                buffer.finalize_last_transaction(cx);
18896                if self.leader_id.is_none() {
18897                    buffer.set_active_selections(
18898                        &self.selections.disjoint_anchors(),
18899                        self.selections.line_mode,
18900                        self.cursor_shape,
18901                        cx,
18902                    );
18903                }
18904            });
18905        }
18906    }
18907
18908    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
18909        cx.emit(EditorEvent::FocusedIn)
18910    }
18911
18912    fn handle_focus_out(
18913        &mut self,
18914        event: FocusOutEvent,
18915        _window: &mut Window,
18916        cx: &mut Context<Self>,
18917    ) {
18918        if event.blurred != self.focus_handle {
18919            self.last_focused_descendant = Some(event.blurred);
18920        }
18921        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
18922    }
18923
18924    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18925        self.blink_manager.update(cx, BlinkManager::disable);
18926        self.buffer
18927            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
18928
18929        if let Some(blame) = self.blame.as_ref() {
18930            blame.update(cx, GitBlame::blur)
18931        }
18932        if !self.hover_state.focused(window, cx) {
18933            hide_hover(self, cx);
18934        }
18935        if !self
18936            .context_menu
18937            .borrow()
18938            .as_ref()
18939            .is_some_and(|context_menu| context_menu.focused(window, cx))
18940        {
18941            self.hide_context_menu(window, cx);
18942        }
18943        self.discard_inline_completion(false, cx);
18944        cx.emit(EditorEvent::Blurred);
18945        cx.notify();
18946    }
18947
18948    pub fn register_action<A: Action>(
18949        &mut self,
18950        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
18951    ) -> Subscription {
18952        let id = self.next_editor_action_id.post_inc();
18953        let listener = Arc::new(listener);
18954        self.editor_actions.borrow_mut().insert(
18955            id,
18956            Box::new(move |window, _| {
18957                let listener = listener.clone();
18958                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
18959                    let action = action.downcast_ref().unwrap();
18960                    if phase == DispatchPhase::Bubble {
18961                        listener(action, window, cx)
18962                    }
18963                })
18964            }),
18965        );
18966
18967        let editor_actions = self.editor_actions.clone();
18968        Subscription::new(move || {
18969            editor_actions.borrow_mut().remove(&id);
18970        })
18971    }
18972
18973    pub fn file_header_size(&self) -> u32 {
18974        FILE_HEADER_HEIGHT
18975    }
18976
18977    pub fn restore(
18978        &mut self,
18979        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
18980        window: &mut Window,
18981        cx: &mut Context<Self>,
18982    ) {
18983        let workspace = self.workspace();
18984        let project = self.project.as_ref();
18985        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
18986            let mut tasks = Vec::new();
18987            for (buffer_id, changes) in revert_changes {
18988                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
18989                    buffer.update(cx, |buffer, cx| {
18990                        buffer.edit(
18991                            changes
18992                                .into_iter()
18993                                .map(|(range, text)| (range, text.to_string())),
18994                            None,
18995                            cx,
18996                        );
18997                    });
18998
18999                    if let Some(project) =
19000                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19001                    {
19002                        project.update(cx, |project, cx| {
19003                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19004                        })
19005                    }
19006                }
19007            }
19008            tasks
19009        });
19010        cx.spawn_in(window, async move |_, cx| {
19011            for (buffer, task) in save_tasks {
19012                let result = task.await;
19013                if result.is_err() {
19014                    let Some(path) = buffer
19015                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19016                        .ok()
19017                    else {
19018                        continue;
19019                    };
19020                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19021                        let Some(task) = cx
19022                            .update_window_entity(&workspace, |workspace, window, cx| {
19023                                workspace
19024                                    .open_path_preview(path, None, false, false, false, window, cx)
19025                            })
19026                            .ok()
19027                        else {
19028                            continue;
19029                        };
19030                        task.await.log_err();
19031                    }
19032                }
19033            }
19034        })
19035        .detach();
19036        self.change_selections(None, window, cx, |selections| selections.refresh());
19037    }
19038
19039    pub fn to_pixel_point(
19040        &self,
19041        source: multi_buffer::Anchor,
19042        editor_snapshot: &EditorSnapshot,
19043        window: &mut Window,
19044    ) -> Option<gpui::Point<Pixels>> {
19045        let source_point = source.to_display_point(editor_snapshot);
19046        self.display_to_pixel_point(source_point, editor_snapshot, window)
19047    }
19048
19049    pub fn display_to_pixel_point(
19050        &self,
19051        source: DisplayPoint,
19052        editor_snapshot: &EditorSnapshot,
19053        window: &mut Window,
19054    ) -> Option<gpui::Point<Pixels>> {
19055        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19056        let text_layout_details = self.text_layout_details(window);
19057        let scroll_top = text_layout_details
19058            .scroll_anchor
19059            .scroll_position(editor_snapshot)
19060            .y;
19061
19062        if source.row().as_f32() < scroll_top.floor() {
19063            return None;
19064        }
19065        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19066        let source_y = line_height * (source.row().as_f32() - scroll_top);
19067        Some(gpui::Point::new(source_x, source_y))
19068    }
19069
19070    pub fn has_visible_completions_menu(&self) -> bool {
19071        !self.edit_prediction_preview_is_active()
19072            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19073                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19074            })
19075    }
19076
19077    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19078        if self.mode.is_minimap() {
19079            return;
19080        }
19081        self.addons
19082            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
19083    }
19084
19085    pub fn unregister_addon<T: Addon>(&mut self) {
19086        self.addons.remove(&std::any::TypeId::of::<T>());
19087    }
19088
19089    pub fn addon<T: Addon>(&self) -> Option<&T> {
19090        let type_id = std::any::TypeId::of::<T>();
19091        self.addons
19092            .get(&type_id)
19093            .and_then(|item| item.to_any().downcast_ref::<T>())
19094    }
19095
19096    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
19097        let type_id = std::any::TypeId::of::<T>();
19098        self.addons
19099            .get_mut(&type_id)
19100            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
19101    }
19102
19103    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
19104        let text_layout_details = self.text_layout_details(window);
19105        let style = &text_layout_details.editor_style;
19106        let font_id = window.text_system().resolve_font(&style.text.font());
19107        let font_size = style.text.font_size.to_pixels(window.rem_size());
19108        let line_height = style.text.line_height_in_pixels(window.rem_size());
19109        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
19110
19111        gpui::Size::new(em_width, line_height)
19112    }
19113
19114    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
19115        self.load_diff_task.clone()
19116    }
19117
19118    fn read_metadata_from_db(
19119        &mut self,
19120        item_id: u64,
19121        workspace_id: WorkspaceId,
19122        window: &mut Window,
19123        cx: &mut Context<Editor>,
19124    ) {
19125        if self.is_singleton(cx)
19126            && !self.mode.is_minimap()
19127            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
19128        {
19129            let buffer_snapshot = OnceCell::new();
19130
19131            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
19132                if !folds.is_empty() {
19133                    let snapshot =
19134                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19135                    self.fold_ranges(
19136                        folds
19137                            .into_iter()
19138                            .map(|(start, end)| {
19139                                snapshot.clip_offset(start, Bias::Left)
19140                                    ..snapshot.clip_offset(end, Bias::Right)
19141                            })
19142                            .collect(),
19143                        false,
19144                        window,
19145                        cx,
19146                    );
19147                }
19148            }
19149
19150            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
19151                if !selections.is_empty() {
19152                    let snapshot =
19153                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19154                    self.change_selections(None, window, cx, |s| {
19155                        s.select_ranges(selections.into_iter().map(|(start, end)| {
19156                            snapshot.clip_offset(start, Bias::Left)
19157                                ..snapshot.clip_offset(end, Bias::Right)
19158                        }));
19159                    });
19160                }
19161            };
19162        }
19163
19164        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
19165    }
19166}
19167
19168fn vim_enabled(cx: &App) -> bool {
19169    cx.global::<SettingsStore>()
19170        .raw_user_settings()
19171        .get("vim_mode")
19172        == Some(&serde_json::Value::Bool(true))
19173}
19174
19175// Consider user intent and default settings
19176fn choose_completion_range(
19177    completion: &Completion,
19178    intent: CompletionIntent,
19179    buffer: &Entity<Buffer>,
19180    cx: &mut Context<Editor>,
19181) -> Range<usize> {
19182    fn should_replace(
19183        completion: &Completion,
19184        insert_range: &Range<text::Anchor>,
19185        intent: CompletionIntent,
19186        completion_mode_setting: LspInsertMode,
19187        buffer: &Buffer,
19188    ) -> bool {
19189        // specific actions take precedence over settings
19190        match intent {
19191            CompletionIntent::CompleteWithInsert => return false,
19192            CompletionIntent::CompleteWithReplace => return true,
19193            CompletionIntent::Complete | CompletionIntent::Compose => {}
19194        }
19195
19196        match completion_mode_setting {
19197            LspInsertMode::Insert => false,
19198            LspInsertMode::Replace => true,
19199            LspInsertMode::ReplaceSubsequence => {
19200                let mut text_to_replace = buffer.chars_for_range(
19201                    buffer.anchor_before(completion.replace_range.start)
19202                        ..buffer.anchor_after(completion.replace_range.end),
19203                );
19204                let mut completion_text = completion.new_text.chars();
19205
19206                // is `text_to_replace` a subsequence of `completion_text`
19207                text_to_replace
19208                    .all(|needle_ch| completion_text.any(|haystack_ch| haystack_ch == needle_ch))
19209            }
19210            LspInsertMode::ReplaceSuffix => {
19211                let range_after_cursor = insert_range.end..completion.replace_range.end;
19212
19213                let text_after_cursor = buffer
19214                    .text_for_range(
19215                        buffer.anchor_before(range_after_cursor.start)
19216                            ..buffer.anchor_after(range_after_cursor.end),
19217                    )
19218                    .collect::<String>();
19219                completion.new_text.ends_with(&text_after_cursor)
19220            }
19221        }
19222    }
19223
19224    let buffer = buffer.read(cx);
19225
19226    if let CompletionSource::Lsp {
19227        insert_range: Some(insert_range),
19228        ..
19229    } = &completion.source
19230    {
19231        let completion_mode_setting =
19232            language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
19233                .completions
19234                .lsp_insert_mode;
19235
19236        if !should_replace(
19237            completion,
19238            &insert_range,
19239            intent,
19240            completion_mode_setting,
19241            buffer,
19242        ) {
19243            return insert_range.to_offset(buffer);
19244        }
19245    }
19246
19247    completion.replace_range.to_offset(buffer)
19248}
19249
19250fn insert_extra_newline_brackets(
19251    buffer: &MultiBufferSnapshot,
19252    range: Range<usize>,
19253    language: &language::LanguageScope,
19254) -> bool {
19255    let leading_whitespace_len = buffer
19256        .reversed_chars_at(range.start)
19257        .take_while(|c| c.is_whitespace() && *c != '\n')
19258        .map(|c| c.len_utf8())
19259        .sum::<usize>();
19260    let trailing_whitespace_len = buffer
19261        .chars_at(range.end)
19262        .take_while(|c| c.is_whitespace() && *c != '\n')
19263        .map(|c| c.len_utf8())
19264        .sum::<usize>();
19265    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
19266
19267    language.brackets().any(|(pair, enabled)| {
19268        let pair_start = pair.start.trim_end();
19269        let pair_end = pair.end.trim_start();
19270
19271        enabled
19272            && pair.newline
19273            && buffer.contains_str_at(range.end, pair_end)
19274            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
19275    })
19276}
19277
19278fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
19279    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
19280        [(buffer, range, _)] => (*buffer, range.clone()),
19281        _ => return false,
19282    };
19283    let pair = {
19284        let mut result: Option<BracketMatch> = None;
19285
19286        for pair in buffer
19287            .all_bracket_ranges(range.clone())
19288            .filter(move |pair| {
19289                pair.open_range.start <= range.start && pair.close_range.end >= range.end
19290            })
19291        {
19292            let len = pair.close_range.end - pair.open_range.start;
19293
19294            if let Some(existing) = &result {
19295                let existing_len = existing.close_range.end - existing.open_range.start;
19296                if len > existing_len {
19297                    continue;
19298                }
19299            }
19300
19301            result = Some(pair);
19302        }
19303
19304        result
19305    };
19306    let Some(pair) = pair else {
19307        return false;
19308    };
19309    pair.newline_only
19310        && buffer
19311            .chars_for_range(pair.open_range.end..range.start)
19312            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
19313            .all(|c| c.is_whitespace() && c != '\n')
19314}
19315
19316fn update_uncommitted_diff_for_buffer(
19317    editor: Entity<Editor>,
19318    project: &Entity<Project>,
19319    buffers: impl IntoIterator<Item = Entity<Buffer>>,
19320    buffer: Entity<MultiBuffer>,
19321    cx: &mut App,
19322) -> Task<()> {
19323    let mut tasks = Vec::new();
19324    project.update(cx, |project, cx| {
19325        for buffer in buffers {
19326            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
19327                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
19328            }
19329        }
19330    });
19331    cx.spawn(async move |cx| {
19332        let diffs = future::join_all(tasks).await;
19333        if editor
19334            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
19335            .unwrap_or(false)
19336        {
19337            return;
19338        }
19339
19340        buffer
19341            .update(cx, |buffer, cx| {
19342                for diff in diffs.into_iter().flatten() {
19343                    buffer.add_diff(diff, cx);
19344                }
19345            })
19346            .ok();
19347    })
19348}
19349
19350fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
19351    let tab_size = tab_size.get() as usize;
19352    let mut width = offset;
19353
19354    for ch in text.chars() {
19355        width += if ch == '\t' {
19356            tab_size - (width % tab_size)
19357        } else {
19358            1
19359        };
19360    }
19361
19362    width - offset
19363}
19364
19365#[cfg(test)]
19366mod tests {
19367    use super::*;
19368
19369    #[test]
19370    fn test_string_size_with_expanded_tabs() {
19371        let nz = |val| NonZeroU32::new(val).unwrap();
19372        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
19373        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
19374        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
19375        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
19376        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
19377        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
19378        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
19379        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
19380    }
19381}
19382
19383/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
19384struct WordBreakingTokenizer<'a> {
19385    input: &'a str,
19386}
19387
19388impl<'a> WordBreakingTokenizer<'a> {
19389    fn new(input: &'a str) -> Self {
19390        Self { input }
19391    }
19392}
19393
19394fn is_char_ideographic(ch: char) -> bool {
19395    use unicode_script::Script::*;
19396    use unicode_script::UnicodeScript;
19397    matches!(ch.script(), Han | Tangut | Yi)
19398}
19399
19400fn is_grapheme_ideographic(text: &str) -> bool {
19401    text.chars().any(is_char_ideographic)
19402}
19403
19404fn is_grapheme_whitespace(text: &str) -> bool {
19405    text.chars().any(|x| x.is_whitespace())
19406}
19407
19408fn should_stay_with_preceding_ideograph(text: &str) -> bool {
19409    text.chars().next().map_or(false, |ch| {
19410        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
19411    })
19412}
19413
19414#[derive(PartialEq, Eq, Debug, Clone, Copy)]
19415enum WordBreakToken<'a> {
19416    Word { token: &'a str, grapheme_len: usize },
19417    InlineWhitespace { token: &'a str, grapheme_len: usize },
19418    Newline,
19419}
19420
19421impl<'a> Iterator for WordBreakingTokenizer<'a> {
19422    /// Yields a span, the count of graphemes in the token, and whether it was
19423    /// whitespace. Note that it also breaks at word boundaries.
19424    type Item = WordBreakToken<'a>;
19425
19426    fn next(&mut self) -> Option<Self::Item> {
19427        use unicode_segmentation::UnicodeSegmentation;
19428        if self.input.is_empty() {
19429            return None;
19430        }
19431
19432        let mut iter = self.input.graphemes(true).peekable();
19433        let mut offset = 0;
19434        let mut grapheme_len = 0;
19435        if let Some(first_grapheme) = iter.next() {
19436            let is_newline = first_grapheme == "\n";
19437            let is_whitespace = is_grapheme_whitespace(first_grapheme);
19438            offset += first_grapheme.len();
19439            grapheme_len += 1;
19440            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
19441                if let Some(grapheme) = iter.peek().copied() {
19442                    if should_stay_with_preceding_ideograph(grapheme) {
19443                        offset += grapheme.len();
19444                        grapheme_len += 1;
19445                    }
19446                }
19447            } else {
19448                let mut words = self.input[offset..].split_word_bound_indices().peekable();
19449                let mut next_word_bound = words.peek().copied();
19450                if next_word_bound.map_or(false, |(i, _)| i == 0) {
19451                    next_word_bound = words.next();
19452                }
19453                while let Some(grapheme) = iter.peek().copied() {
19454                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
19455                        break;
19456                    };
19457                    if is_grapheme_whitespace(grapheme) != is_whitespace
19458                        || (grapheme == "\n") != is_newline
19459                    {
19460                        break;
19461                    };
19462                    offset += grapheme.len();
19463                    grapheme_len += 1;
19464                    iter.next();
19465                }
19466            }
19467            let token = &self.input[..offset];
19468            self.input = &self.input[offset..];
19469            if token == "\n" {
19470                Some(WordBreakToken::Newline)
19471            } else if is_whitespace {
19472                Some(WordBreakToken::InlineWhitespace {
19473                    token,
19474                    grapheme_len,
19475                })
19476            } else {
19477                Some(WordBreakToken::Word {
19478                    token,
19479                    grapheme_len,
19480                })
19481            }
19482        } else {
19483            None
19484        }
19485    }
19486}
19487
19488#[test]
19489fn test_word_breaking_tokenizer() {
19490    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
19491        ("", &[]),
19492        ("  ", &[whitespace("  ", 2)]),
19493        ("Ʒ", &[word("Ʒ", 1)]),
19494        ("Ǽ", &[word("Ǽ", 1)]),
19495        ("", &[word("", 1)]),
19496        ("⋑⋑", &[word("⋑⋑", 2)]),
19497        (
19498            "原理,进而",
19499            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
19500        ),
19501        (
19502            "hello world",
19503            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
19504        ),
19505        (
19506            "hello, world",
19507            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
19508        ),
19509        (
19510            "  hello world",
19511            &[
19512                whitespace("  ", 2),
19513                word("hello", 5),
19514                whitespace(" ", 1),
19515                word("world", 5),
19516            ],
19517        ),
19518        (
19519            "这是什么 \n 钢笔",
19520            &[
19521                word("", 1),
19522                word("", 1),
19523                word("", 1),
19524                word("", 1),
19525                whitespace(" ", 1),
19526                newline(),
19527                whitespace(" ", 1),
19528                word("", 1),
19529                word("", 1),
19530            ],
19531        ),
19532        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
19533    ];
19534
19535    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19536        WordBreakToken::Word {
19537            token,
19538            grapheme_len,
19539        }
19540    }
19541
19542    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19543        WordBreakToken::InlineWhitespace {
19544            token,
19545            grapheme_len,
19546        }
19547    }
19548
19549    fn newline() -> WordBreakToken<'static> {
19550        WordBreakToken::Newline
19551    }
19552
19553    for (input, result) in tests {
19554        assert_eq!(
19555            WordBreakingTokenizer::new(input)
19556                .collect::<Vec<_>>()
19557                .as_slice(),
19558            *result,
19559        );
19560    }
19561}
19562
19563fn wrap_with_prefix(
19564    line_prefix: String,
19565    unwrapped_text: String,
19566    wrap_column: usize,
19567    tab_size: NonZeroU32,
19568    preserve_existing_whitespace: bool,
19569) -> String {
19570    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
19571    let mut wrapped_text = String::new();
19572    let mut current_line = line_prefix.clone();
19573
19574    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
19575    let mut current_line_len = line_prefix_len;
19576    let mut in_whitespace = false;
19577    for token in tokenizer {
19578        let have_preceding_whitespace = in_whitespace;
19579        match token {
19580            WordBreakToken::Word {
19581                token,
19582                grapheme_len,
19583            } => {
19584                in_whitespace = false;
19585                if current_line_len + grapheme_len > wrap_column
19586                    && current_line_len != line_prefix_len
19587                {
19588                    wrapped_text.push_str(current_line.trim_end());
19589                    wrapped_text.push('\n');
19590                    current_line.truncate(line_prefix.len());
19591                    current_line_len = line_prefix_len;
19592                }
19593                current_line.push_str(token);
19594                current_line_len += grapheme_len;
19595            }
19596            WordBreakToken::InlineWhitespace {
19597                mut token,
19598                mut grapheme_len,
19599            } => {
19600                in_whitespace = true;
19601                if have_preceding_whitespace && !preserve_existing_whitespace {
19602                    continue;
19603                }
19604                if !preserve_existing_whitespace {
19605                    token = " ";
19606                    grapheme_len = 1;
19607                }
19608                if current_line_len + grapheme_len > wrap_column {
19609                    wrapped_text.push_str(current_line.trim_end());
19610                    wrapped_text.push('\n');
19611                    current_line.truncate(line_prefix.len());
19612                    current_line_len = line_prefix_len;
19613                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
19614                    current_line.push_str(token);
19615                    current_line_len += grapheme_len;
19616                }
19617            }
19618            WordBreakToken::Newline => {
19619                in_whitespace = true;
19620                if preserve_existing_whitespace {
19621                    wrapped_text.push_str(current_line.trim_end());
19622                    wrapped_text.push('\n');
19623                    current_line.truncate(line_prefix.len());
19624                    current_line_len = line_prefix_len;
19625                } else if have_preceding_whitespace {
19626                    continue;
19627                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
19628                {
19629                    wrapped_text.push_str(current_line.trim_end());
19630                    wrapped_text.push('\n');
19631                    current_line.truncate(line_prefix.len());
19632                    current_line_len = line_prefix_len;
19633                } else if current_line_len != line_prefix_len {
19634                    current_line.push(' ');
19635                    current_line_len += 1;
19636                }
19637            }
19638        }
19639    }
19640
19641    if !current_line.is_empty() {
19642        wrapped_text.push_str(&current_line);
19643    }
19644    wrapped_text
19645}
19646
19647#[test]
19648fn test_wrap_with_prefix() {
19649    assert_eq!(
19650        wrap_with_prefix(
19651            "# ".to_string(),
19652            "abcdefg".to_string(),
19653            4,
19654            NonZeroU32::new(4).unwrap(),
19655            false,
19656        ),
19657        "# abcdefg"
19658    );
19659    assert_eq!(
19660        wrap_with_prefix(
19661            "".to_string(),
19662            "\thello world".to_string(),
19663            8,
19664            NonZeroU32::new(4).unwrap(),
19665            false,
19666        ),
19667        "hello\nworld"
19668    );
19669    assert_eq!(
19670        wrap_with_prefix(
19671            "// ".to_string(),
19672            "xx \nyy zz aa bb cc".to_string(),
19673            12,
19674            NonZeroU32::new(4).unwrap(),
19675            false,
19676        ),
19677        "// xx yy zz\n// aa bb cc"
19678    );
19679    assert_eq!(
19680        wrap_with_prefix(
19681            String::new(),
19682            "这是什么 \n 钢笔".to_string(),
19683            3,
19684            NonZeroU32::new(4).unwrap(),
19685            false,
19686        ),
19687        "这是什\n么 钢\n"
19688    );
19689}
19690
19691pub trait CollaborationHub {
19692    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
19693    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
19694    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
19695}
19696
19697impl CollaborationHub for Entity<Project> {
19698    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
19699        self.read(cx).collaborators()
19700    }
19701
19702    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
19703        self.read(cx).user_store().read(cx).participant_indices()
19704    }
19705
19706    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
19707        let this = self.read(cx);
19708        let user_ids = this.collaborators().values().map(|c| c.user_id);
19709        this.user_store().read_with(cx, |user_store, cx| {
19710            user_store.participant_names(user_ids, cx)
19711        })
19712    }
19713}
19714
19715pub trait SemanticsProvider {
19716    fn hover(
19717        &self,
19718        buffer: &Entity<Buffer>,
19719        position: text::Anchor,
19720        cx: &mut App,
19721    ) -> Option<Task<Vec<project::Hover>>>;
19722
19723    fn inline_values(
19724        &self,
19725        buffer_handle: Entity<Buffer>,
19726        range: Range<text::Anchor>,
19727        cx: &mut App,
19728    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19729
19730    fn inlay_hints(
19731        &self,
19732        buffer_handle: Entity<Buffer>,
19733        range: Range<text::Anchor>,
19734        cx: &mut App,
19735    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19736
19737    fn resolve_inlay_hint(
19738        &self,
19739        hint: InlayHint,
19740        buffer_handle: Entity<Buffer>,
19741        server_id: LanguageServerId,
19742        cx: &mut App,
19743    ) -> Option<Task<anyhow::Result<InlayHint>>>;
19744
19745    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
19746
19747    fn document_highlights(
19748        &self,
19749        buffer: &Entity<Buffer>,
19750        position: text::Anchor,
19751        cx: &mut App,
19752    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
19753
19754    fn definitions(
19755        &self,
19756        buffer: &Entity<Buffer>,
19757        position: text::Anchor,
19758        kind: GotoDefinitionKind,
19759        cx: &mut App,
19760    ) -> Option<Task<Result<Vec<LocationLink>>>>;
19761
19762    fn range_for_rename(
19763        &self,
19764        buffer: &Entity<Buffer>,
19765        position: text::Anchor,
19766        cx: &mut App,
19767    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
19768
19769    fn perform_rename(
19770        &self,
19771        buffer: &Entity<Buffer>,
19772        position: text::Anchor,
19773        new_name: String,
19774        cx: &mut App,
19775    ) -> Option<Task<Result<ProjectTransaction>>>;
19776}
19777
19778pub trait CompletionProvider {
19779    fn completions(
19780        &self,
19781        excerpt_id: ExcerptId,
19782        buffer: &Entity<Buffer>,
19783        buffer_position: text::Anchor,
19784        trigger: CompletionContext,
19785        window: &mut Window,
19786        cx: &mut Context<Editor>,
19787    ) -> Task<Result<Option<Vec<Completion>>>>;
19788
19789    fn resolve_completions(
19790        &self,
19791        buffer: Entity<Buffer>,
19792        completion_indices: Vec<usize>,
19793        completions: Rc<RefCell<Box<[Completion]>>>,
19794        cx: &mut Context<Editor>,
19795    ) -> Task<Result<bool>>;
19796
19797    fn apply_additional_edits_for_completion(
19798        &self,
19799        _buffer: Entity<Buffer>,
19800        _completions: Rc<RefCell<Box<[Completion]>>>,
19801        _completion_index: usize,
19802        _push_to_history: bool,
19803        _cx: &mut Context<Editor>,
19804    ) -> Task<Result<Option<language::Transaction>>> {
19805        Task::ready(Ok(None))
19806    }
19807
19808    fn is_completion_trigger(
19809        &self,
19810        buffer: &Entity<Buffer>,
19811        position: language::Anchor,
19812        text: &str,
19813        trigger_in_words: bool,
19814        cx: &mut Context<Editor>,
19815    ) -> bool;
19816
19817    fn sort_completions(&self) -> bool {
19818        true
19819    }
19820
19821    fn filter_completions(&self) -> bool {
19822        true
19823    }
19824}
19825
19826pub trait CodeActionProvider {
19827    fn id(&self) -> Arc<str>;
19828
19829    fn code_actions(
19830        &self,
19831        buffer: &Entity<Buffer>,
19832        range: Range<text::Anchor>,
19833        window: &mut Window,
19834        cx: &mut App,
19835    ) -> Task<Result<Vec<CodeAction>>>;
19836
19837    fn apply_code_action(
19838        &self,
19839        buffer_handle: Entity<Buffer>,
19840        action: CodeAction,
19841        excerpt_id: ExcerptId,
19842        push_to_history: bool,
19843        window: &mut Window,
19844        cx: &mut App,
19845    ) -> Task<Result<ProjectTransaction>>;
19846}
19847
19848impl CodeActionProvider for Entity<Project> {
19849    fn id(&self) -> Arc<str> {
19850        "project".into()
19851    }
19852
19853    fn code_actions(
19854        &self,
19855        buffer: &Entity<Buffer>,
19856        range: Range<text::Anchor>,
19857        _window: &mut Window,
19858        cx: &mut App,
19859    ) -> Task<Result<Vec<CodeAction>>> {
19860        self.update(cx, |project, cx| {
19861            let code_lens = project.code_lens(buffer, range.clone(), cx);
19862            let code_actions = project.code_actions(buffer, range, None, cx);
19863            cx.background_spawn(async move {
19864                let (code_lens, code_actions) = join(code_lens, code_actions).await;
19865                Ok(code_lens
19866                    .context("code lens fetch")?
19867                    .into_iter()
19868                    .chain(code_actions.context("code action fetch")?)
19869                    .collect())
19870            })
19871        })
19872    }
19873
19874    fn apply_code_action(
19875        &self,
19876        buffer_handle: Entity<Buffer>,
19877        action: CodeAction,
19878        _excerpt_id: ExcerptId,
19879        push_to_history: bool,
19880        _window: &mut Window,
19881        cx: &mut App,
19882    ) -> Task<Result<ProjectTransaction>> {
19883        self.update(cx, |project, cx| {
19884            project.apply_code_action(buffer_handle, action, push_to_history, cx)
19885        })
19886    }
19887}
19888
19889fn snippet_completions(
19890    project: &Project,
19891    buffer: &Entity<Buffer>,
19892    buffer_position: text::Anchor,
19893    cx: &mut App,
19894) -> Task<Result<Vec<Completion>>> {
19895    let languages = buffer.read(cx).languages_at(buffer_position);
19896    let snippet_store = project.snippets().read(cx);
19897
19898    let scopes: Vec<_> = languages
19899        .iter()
19900        .filter_map(|language| {
19901            let language_name = language.lsp_id();
19902            let snippets = snippet_store.snippets_for(Some(language_name), cx);
19903
19904            if snippets.is_empty() {
19905                None
19906            } else {
19907                Some((language.default_scope(), snippets))
19908            }
19909        })
19910        .collect();
19911
19912    if scopes.is_empty() {
19913        return Task::ready(Ok(vec![]));
19914    }
19915
19916    let snapshot = buffer.read(cx).text_snapshot();
19917    let chars: String = snapshot
19918        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
19919        .collect();
19920    let executor = cx.background_executor().clone();
19921
19922    cx.background_spawn(async move {
19923        let mut all_results: Vec<Completion> = Vec::new();
19924        for (scope, snippets) in scopes.into_iter() {
19925            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
19926            let mut last_word = chars
19927                .chars()
19928                .take_while(|c| classifier.is_word(*c))
19929                .collect::<String>();
19930            last_word = last_word.chars().rev().collect();
19931
19932            if last_word.is_empty() {
19933                return Ok(vec![]);
19934            }
19935
19936            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
19937            let to_lsp = |point: &text::Anchor| {
19938                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
19939                point_to_lsp(end)
19940            };
19941            let lsp_end = to_lsp(&buffer_position);
19942
19943            let candidates = snippets
19944                .iter()
19945                .enumerate()
19946                .flat_map(|(ix, snippet)| {
19947                    snippet
19948                        .prefix
19949                        .iter()
19950                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
19951                })
19952                .collect::<Vec<StringMatchCandidate>>();
19953
19954            let mut matches = fuzzy::match_strings(
19955                &candidates,
19956                &last_word,
19957                last_word.chars().any(|c| c.is_uppercase()),
19958                100,
19959                &Default::default(),
19960                executor.clone(),
19961            )
19962            .await;
19963
19964            // Remove all candidates where the query's start does not match the start of any word in the candidate
19965            if let Some(query_start) = last_word.chars().next() {
19966                matches.retain(|string_match| {
19967                    split_words(&string_match.string).any(|word| {
19968                        // Check that the first codepoint of the word as lowercase matches the first
19969                        // codepoint of the query as lowercase
19970                        word.chars()
19971                            .flat_map(|codepoint| codepoint.to_lowercase())
19972                            .zip(query_start.to_lowercase())
19973                            .all(|(word_cp, query_cp)| word_cp == query_cp)
19974                    })
19975                });
19976            }
19977
19978            let matched_strings = matches
19979                .into_iter()
19980                .map(|m| m.string)
19981                .collect::<HashSet<_>>();
19982
19983            let mut result: Vec<Completion> = snippets
19984                .iter()
19985                .filter_map(|snippet| {
19986                    let matching_prefix = snippet
19987                        .prefix
19988                        .iter()
19989                        .find(|prefix| matched_strings.contains(*prefix))?;
19990                    let start = as_offset - last_word.len();
19991                    let start = snapshot.anchor_before(start);
19992                    let range = start..buffer_position;
19993                    let lsp_start = to_lsp(&start);
19994                    let lsp_range = lsp::Range {
19995                        start: lsp_start,
19996                        end: lsp_end,
19997                    };
19998                    Some(Completion {
19999                        replace_range: range,
20000                        new_text: snippet.body.clone(),
20001                        source: CompletionSource::Lsp {
20002                            insert_range: None,
20003                            server_id: LanguageServerId(usize::MAX),
20004                            resolved: true,
20005                            lsp_completion: Box::new(lsp::CompletionItem {
20006                                label: snippet.prefix.first().unwrap().clone(),
20007                                kind: Some(CompletionItemKind::SNIPPET),
20008                                label_details: snippet.description.as_ref().map(|description| {
20009                                    lsp::CompletionItemLabelDetails {
20010                                        detail: Some(description.clone()),
20011                                        description: None,
20012                                    }
20013                                }),
20014                                insert_text_format: Some(InsertTextFormat::SNIPPET),
20015                                text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
20016                                    lsp::InsertReplaceEdit {
20017                                        new_text: snippet.body.clone(),
20018                                        insert: lsp_range,
20019                                        replace: lsp_range,
20020                                    },
20021                                )),
20022                                filter_text: Some(snippet.body.clone()),
20023                                sort_text: Some(char::MAX.to_string()),
20024                                ..lsp::CompletionItem::default()
20025                            }),
20026                            lsp_defaults: None,
20027                        },
20028                        label: CodeLabel {
20029                            text: matching_prefix.clone(),
20030                            runs: Vec::new(),
20031                            filter_range: 0..matching_prefix.len(),
20032                        },
20033                        icon_path: None,
20034                        documentation: Some(
20035                            CompletionDocumentation::SingleLineAndMultiLinePlainText {
20036                                single_line: snippet.name.clone().into(),
20037                                plain_text: snippet
20038                                    .description
20039                                    .clone()
20040                                    .map(|description| description.into()),
20041                            },
20042                        ),
20043                        insert_text_mode: None,
20044                        confirm: None,
20045                    })
20046                })
20047                .collect();
20048
20049            all_results.append(&mut result);
20050        }
20051
20052        Ok(all_results)
20053    })
20054}
20055
20056impl CompletionProvider for Entity<Project> {
20057    fn completions(
20058        &self,
20059        _excerpt_id: ExcerptId,
20060        buffer: &Entity<Buffer>,
20061        buffer_position: text::Anchor,
20062        options: CompletionContext,
20063        _window: &mut Window,
20064        cx: &mut Context<Editor>,
20065    ) -> Task<Result<Option<Vec<Completion>>>> {
20066        self.update(cx, |project, cx| {
20067            let snippets = snippet_completions(project, buffer, buffer_position, cx);
20068            let project_completions = project.completions(buffer, buffer_position, options, cx);
20069            cx.background_spawn(async move {
20070                let snippets_completions = snippets.await?;
20071                match project_completions.await? {
20072                    Some(mut completions) => {
20073                        completions.extend(snippets_completions);
20074                        Ok(Some(completions))
20075                    }
20076                    None => {
20077                        if snippets_completions.is_empty() {
20078                            Ok(None)
20079                        } else {
20080                            Ok(Some(snippets_completions))
20081                        }
20082                    }
20083                }
20084            })
20085        })
20086    }
20087
20088    fn resolve_completions(
20089        &self,
20090        buffer: Entity<Buffer>,
20091        completion_indices: Vec<usize>,
20092        completions: Rc<RefCell<Box<[Completion]>>>,
20093        cx: &mut Context<Editor>,
20094    ) -> Task<Result<bool>> {
20095        self.update(cx, |project, cx| {
20096            project.lsp_store().update(cx, |lsp_store, cx| {
20097                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
20098            })
20099        })
20100    }
20101
20102    fn apply_additional_edits_for_completion(
20103        &self,
20104        buffer: Entity<Buffer>,
20105        completions: Rc<RefCell<Box<[Completion]>>>,
20106        completion_index: usize,
20107        push_to_history: bool,
20108        cx: &mut Context<Editor>,
20109    ) -> Task<Result<Option<language::Transaction>>> {
20110        self.update(cx, |project, cx| {
20111            project.lsp_store().update(cx, |lsp_store, cx| {
20112                lsp_store.apply_additional_edits_for_completion(
20113                    buffer,
20114                    completions,
20115                    completion_index,
20116                    push_to_history,
20117                    cx,
20118                )
20119            })
20120        })
20121    }
20122
20123    fn is_completion_trigger(
20124        &self,
20125        buffer: &Entity<Buffer>,
20126        position: language::Anchor,
20127        text: &str,
20128        trigger_in_words: bool,
20129        cx: &mut Context<Editor>,
20130    ) -> bool {
20131        let mut chars = text.chars();
20132        let char = if let Some(char) = chars.next() {
20133            char
20134        } else {
20135            return false;
20136        };
20137        if chars.next().is_some() {
20138            return false;
20139        }
20140
20141        let buffer = buffer.read(cx);
20142        let snapshot = buffer.snapshot();
20143        if !snapshot.settings_at(position, cx).show_completions_on_input {
20144            return false;
20145        }
20146        let classifier = snapshot.char_classifier_at(position).for_completion(true);
20147        if trigger_in_words && classifier.is_word(char) {
20148            return true;
20149        }
20150
20151        buffer.completion_triggers().contains(text)
20152    }
20153}
20154
20155impl SemanticsProvider for Entity<Project> {
20156    fn hover(
20157        &self,
20158        buffer: &Entity<Buffer>,
20159        position: text::Anchor,
20160        cx: &mut App,
20161    ) -> Option<Task<Vec<project::Hover>>> {
20162        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
20163    }
20164
20165    fn document_highlights(
20166        &self,
20167        buffer: &Entity<Buffer>,
20168        position: text::Anchor,
20169        cx: &mut App,
20170    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
20171        Some(self.update(cx, |project, cx| {
20172            project.document_highlights(buffer, position, cx)
20173        }))
20174    }
20175
20176    fn definitions(
20177        &self,
20178        buffer: &Entity<Buffer>,
20179        position: text::Anchor,
20180        kind: GotoDefinitionKind,
20181        cx: &mut App,
20182    ) -> Option<Task<Result<Vec<LocationLink>>>> {
20183        Some(self.update(cx, |project, cx| match kind {
20184            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
20185            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
20186            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
20187            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
20188        }))
20189    }
20190
20191    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
20192        // TODO: make this work for remote projects
20193        self.update(cx, |project, cx| {
20194            if project
20195                .active_debug_session(cx)
20196                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
20197            {
20198                return true;
20199            }
20200
20201            buffer.update(cx, |buffer, cx| {
20202                project.any_language_server_supports_inlay_hints(buffer, cx)
20203            })
20204        })
20205    }
20206
20207    fn inline_values(
20208        &self,
20209        buffer_handle: Entity<Buffer>,
20210        range: Range<text::Anchor>,
20211        cx: &mut App,
20212    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20213        self.update(cx, |project, cx| {
20214            let (session, active_stack_frame) = project.active_debug_session(cx)?;
20215
20216            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
20217        })
20218    }
20219
20220    fn inlay_hints(
20221        &self,
20222        buffer_handle: Entity<Buffer>,
20223        range: Range<text::Anchor>,
20224        cx: &mut App,
20225    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20226        Some(self.update(cx, |project, cx| {
20227            project.inlay_hints(buffer_handle, range, cx)
20228        }))
20229    }
20230
20231    fn resolve_inlay_hint(
20232        &self,
20233        hint: InlayHint,
20234        buffer_handle: Entity<Buffer>,
20235        server_id: LanguageServerId,
20236        cx: &mut App,
20237    ) -> Option<Task<anyhow::Result<InlayHint>>> {
20238        Some(self.update(cx, |project, cx| {
20239            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
20240        }))
20241    }
20242
20243    fn range_for_rename(
20244        &self,
20245        buffer: &Entity<Buffer>,
20246        position: text::Anchor,
20247        cx: &mut App,
20248    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
20249        Some(self.update(cx, |project, cx| {
20250            let buffer = buffer.clone();
20251            let task = project.prepare_rename(buffer.clone(), position, cx);
20252            cx.spawn(async move |_, cx| {
20253                Ok(match task.await? {
20254                    PrepareRenameResponse::Success(range) => Some(range),
20255                    PrepareRenameResponse::InvalidPosition => None,
20256                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
20257                        // Fallback on using TreeSitter info to determine identifier range
20258                        buffer.update(cx, |buffer, _| {
20259                            let snapshot = buffer.snapshot();
20260                            let (range, kind) = snapshot.surrounding_word(position);
20261                            if kind != Some(CharKind::Word) {
20262                                return None;
20263                            }
20264                            Some(
20265                                snapshot.anchor_before(range.start)
20266                                    ..snapshot.anchor_after(range.end),
20267                            )
20268                        })?
20269                    }
20270                })
20271            })
20272        }))
20273    }
20274
20275    fn perform_rename(
20276        &self,
20277        buffer: &Entity<Buffer>,
20278        position: text::Anchor,
20279        new_name: String,
20280        cx: &mut App,
20281    ) -> Option<Task<Result<ProjectTransaction>>> {
20282        Some(self.update(cx, |project, cx| {
20283            project.perform_rename(buffer.clone(), position, new_name, cx)
20284        }))
20285    }
20286}
20287
20288fn inlay_hint_settings(
20289    location: Anchor,
20290    snapshot: &MultiBufferSnapshot,
20291    cx: &mut Context<Editor>,
20292) -> InlayHintSettings {
20293    let file = snapshot.file_at(location);
20294    let language = snapshot.language_at(location).map(|l| l.name());
20295    language_settings(language, file, cx).inlay_hints
20296}
20297
20298fn consume_contiguous_rows(
20299    contiguous_row_selections: &mut Vec<Selection<Point>>,
20300    selection: &Selection<Point>,
20301    display_map: &DisplaySnapshot,
20302    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
20303) -> (MultiBufferRow, MultiBufferRow) {
20304    contiguous_row_selections.push(selection.clone());
20305    let start_row = MultiBufferRow(selection.start.row);
20306    let mut end_row = ending_row(selection, display_map);
20307
20308    while let Some(next_selection) = selections.peek() {
20309        if next_selection.start.row <= end_row.0 {
20310            end_row = ending_row(next_selection, display_map);
20311            contiguous_row_selections.push(selections.next().unwrap().clone());
20312        } else {
20313            break;
20314        }
20315    }
20316    (start_row, end_row)
20317}
20318
20319fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
20320    if next_selection.end.column > 0 || next_selection.is_empty() {
20321        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
20322    } else {
20323        MultiBufferRow(next_selection.end.row)
20324    }
20325}
20326
20327impl EditorSnapshot {
20328    pub fn remote_selections_in_range<'a>(
20329        &'a self,
20330        range: &'a Range<Anchor>,
20331        collaboration_hub: &dyn CollaborationHub,
20332        cx: &'a App,
20333    ) -> impl 'a + Iterator<Item = RemoteSelection> {
20334        let participant_names = collaboration_hub.user_names(cx);
20335        let participant_indices = collaboration_hub.user_participant_indices(cx);
20336        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
20337        let collaborators_by_replica_id = collaborators_by_peer_id
20338            .values()
20339            .map(|collaborator| (collaborator.replica_id, collaborator))
20340            .collect::<HashMap<_, _>>();
20341        self.buffer_snapshot
20342            .selections_in_range(range, false)
20343            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
20344                if replica_id == AGENT_REPLICA_ID {
20345                    Some(RemoteSelection {
20346                        replica_id,
20347                        selection,
20348                        cursor_shape,
20349                        line_mode,
20350                        collaborator_id: CollaboratorId::Agent,
20351                        user_name: Some("Agent".into()),
20352                        color: cx.theme().players().agent(),
20353                    })
20354                } else {
20355                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
20356                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
20357                    let user_name = participant_names.get(&collaborator.user_id).cloned();
20358                    Some(RemoteSelection {
20359                        replica_id,
20360                        selection,
20361                        cursor_shape,
20362                        line_mode,
20363                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
20364                        user_name,
20365                        color: if let Some(index) = participant_index {
20366                            cx.theme().players().color_for_participant(index.0)
20367                        } else {
20368                            cx.theme().players().absent()
20369                        },
20370                    })
20371                }
20372            })
20373    }
20374
20375    pub fn hunks_for_ranges(
20376        &self,
20377        ranges: impl IntoIterator<Item = Range<Point>>,
20378    ) -> Vec<MultiBufferDiffHunk> {
20379        let mut hunks = Vec::new();
20380        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
20381            HashMap::default();
20382        for query_range in ranges {
20383            let query_rows =
20384                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
20385            for hunk in self.buffer_snapshot.diff_hunks_in_range(
20386                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
20387            ) {
20388                // Include deleted hunks that are adjacent to the query range, because
20389                // otherwise they would be missed.
20390                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
20391                if hunk.status().is_deleted() {
20392                    intersects_range |= hunk.row_range.start == query_rows.end;
20393                    intersects_range |= hunk.row_range.end == query_rows.start;
20394                }
20395                if intersects_range {
20396                    if !processed_buffer_rows
20397                        .entry(hunk.buffer_id)
20398                        .or_default()
20399                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
20400                    {
20401                        continue;
20402                    }
20403                    hunks.push(hunk);
20404                }
20405            }
20406        }
20407
20408        hunks
20409    }
20410
20411    fn display_diff_hunks_for_rows<'a>(
20412        &'a self,
20413        display_rows: Range<DisplayRow>,
20414        folded_buffers: &'a HashSet<BufferId>,
20415    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
20416        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
20417        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
20418
20419        self.buffer_snapshot
20420            .diff_hunks_in_range(buffer_start..buffer_end)
20421            .filter_map(|hunk| {
20422                if folded_buffers.contains(&hunk.buffer_id) {
20423                    return None;
20424                }
20425
20426                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
20427                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
20428
20429                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
20430                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
20431
20432                let display_hunk = if hunk_display_start.column() != 0 {
20433                    DisplayDiffHunk::Folded {
20434                        display_row: hunk_display_start.row(),
20435                    }
20436                } else {
20437                    let mut end_row = hunk_display_end.row();
20438                    if hunk_display_end.column() > 0 {
20439                        end_row.0 += 1;
20440                    }
20441                    let is_created_file = hunk.is_created_file();
20442                    DisplayDiffHunk::Unfolded {
20443                        status: hunk.status(),
20444                        diff_base_byte_range: hunk.diff_base_byte_range,
20445                        display_row_range: hunk_display_start.row()..end_row,
20446                        multi_buffer_range: Anchor::range_in_buffer(
20447                            hunk.excerpt_id,
20448                            hunk.buffer_id,
20449                            hunk.buffer_range,
20450                        ),
20451                        is_created_file,
20452                    }
20453                };
20454
20455                Some(display_hunk)
20456            })
20457    }
20458
20459    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
20460        self.display_snapshot.buffer_snapshot.language_at(position)
20461    }
20462
20463    pub fn is_focused(&self) -> bool {
20464        self.is_focused
20465    }
20466
20467    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
20468        self.placeholder_text.as_ref()
20469    }
20470
20471    pub fn scroll_position(&self) -> gpui::Point<f32> {
20472        self.scroll_anchor.scroll_position(&self.display_snapshot)
20473    }
20474
20475    fn gutter_dimensions(
20476        &self,
20477        font_id: FontId,
20478        font_size: Pixels,
20479        max_line_number_width: Pixels,
20480        cx: &App,
20481    ) -> Option<GutterDimensions> {
20482        if !self.show_gutter {
20483            return None;
20484        }
20485
20486        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
20487        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
20488
20489        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
20490            matches!(
20491                ProjectSettings::get_global(cx).git.git_gutter,
20492                Some(GitGutterSetting::TrackedFiles)
20493            )
20494        });
20495        let gutter_settings = EditorSettings::get_global(cx).gutter;
20496        let show_line_numbers = self
20497            .show_line_numbers
20498            .unwrap_or(gutter_settings.line_numbers);
20499        let line_gutter_width = if show_line_numbers {
20500            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
20501            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
20502            max_line_number_width.max(min_width_for_number_on_gutter)
20503        } else {
20504            0.0.into()
20505        };
20506
20507        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
20508        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
20509
20510        let git_blame_entries_width =
20511            self.git_blame_gutter_max_author_length
20512                .map(|max_author_length| {
20513                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20514                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
20515
20516                    /// The number of characters to dedicate to gaps and margins.
20517                    const SPACING_WIDTH: usize = 4;
20518
20519                    let max_char_count = max_author_length.min(renderer.max_author_length())
20520                        + ::git::SHORT_SHA_LENGTH
20521                        + MAX_RELATIVE_TIMESTAMP.len()
20522                        + SPACING_WIDTH;
20523
20524                    em_advance * max_char_count
20525                });
20526
20527        let is_singleton = self.buffer_snapshot.is_singleton();
20528
20529        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
20530        left_padding += if !is_singleton {
20531            em_width * 4.0
20532        } else if show_runnables || show_breakpoints {
20533            em_width * 3.0
20534        } else if show_git_gutter && show_line_numbers {
20535            em_width * 2.0
20536        } else if show_git_gutter || show_line_numbers {
20537            em_width
20538        } else {
20539            px(0.)
20540        };
20541
20542        let shows_folds = is_singleton && gutter_settings.folds;
20543
20544        let right_padding = if shows_folds && show_line_numbers {
20545            em_width * 4.0
20546        } else if shows_folds || (!is_singleton && show_line_numbers) {
20547            em_width * 3.0
20548        } else if show_line_numbers {
20549            em_width
20550        } else {
20551            px(0.)
20552        };
20553
20554        Some(GutterDimensions {
20555            left_padding,
20556            right_padding,
20557            width: line_gutter_width + left_padding + right_padding,
20558            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
20559            git_blame_entries_width,
20560        })
20561    }
20562
20563    pub fn render_crease_toggle(
20564        &self,
20565        buffer_row: MultiBufferRow,
20566        row_contains_cursor: bool,
20567        editor: Entity<Editor>,
20568        window: &mut Window,
20569        cx: &mut App,
20570    ) -> Option<AnyElement> {
20571        let folded = self.is_line_folded(buffer_row);
20572        let mut is_foldable = false;
20573
20574        if let Some(crease) = self
20575            .crease_snapshot
20576            .query_row(buffer_row, &self.buffer_snapshot)
20577        {
20578            is_foldable = true;
20579            match crease {
20580                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
20581                    if let Some(render_toggle) = render_toggle {
20582                        let toggle_callback =
20583                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
20584                                if folded {
20585                                    editor.update(cx, |editor, cx| {
20586                                        editor.fold_at(buffer_row, window, cx)
20587                                    });
20588                                } else {
20589                                    editor.update(cx, |editor, cx| {
20590                                        editor.unfold_at(buffer_row, window, cx)
20591                                    });
20592                                }
20593                            });
20594                        return Some((render_toggle)(
20595                            buffer_row,
20596                            folded,
20597                            toggle_callback,
20598                            window,
20599                            cx,
20600                        ));
20601                    }
20602                }
20603            }
20604        }
20605
20606        is_foldable |= self.starts_indent(buffer_row);
20607
20608        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
20609            Some(
20610                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
20611                    .toggle_state(folded)
20612                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
20613                        if folded {
20614                            this.unfold_at(buffer_row, window, cx);
20615                        } else {
20616                            this.fold_at(buffer_row, window, cx);
20617                        }
20618                    }))
20619                    .into_any_element(),
20620            )
20621        } else {
20622            None
20623        }
20624    }
20625
20626    pub fn render_crease_trailer(
20627        &self,
20628        buffer_row: MultiBufferRow,
20629        window: &mut Window,
20630        cx: &mut App,
20631    ) -> Option<AnyElement> {
20632        let folded = self.is_line_folded(buffer_row);
20633        if let Crease::Inline { render_trailer, .. } = self
20634            .crease_snapshot
20635            .query_row(buffer_row, &self.buffer_snapshot)?
20636        {
20637            let render_trailer = render_trailer.as_ref()?;
20638            Some(render_trailer(buffer_row, folded, window, cx))
20639        } else {
20640            None
20641        }
20642    }
20643}
20644
20645impl Deref for EditorSnapshot {
20646    type Target = DisplaySnapshot;
20647
20648    fn deref(&self) -> &Self::Target {
20649        &self.display_snapshot
20650    }
20651}
20652
20653#[derive(Clone, Debug, PartialEq, Eq)]
20654pub enum EditorEvent {
20655    InputIgnored {
20656        text: Arc<str>,
20657    },
20658    InputHandled {
20659        utf16_range_to_replace: Option<Range<isize>>,
20660        text: Arc<str>,
20661    },
20662    ExcerptsAdded {
20663        buffer: Entity<Buffer>,
20664        predecessor: ExcerptId,
20665        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
20666    },
20667    ExcerptsRemoved {
20668        ids: Vec<ExcerptId>,
20669        removed_buffer_ids: Vec<BufferId>,
20670    },
20671    BufferFoldToggled {
20672        ids: Vec<ExcerptId>,
20673        folded: bool,
20674    },
20675    ExcerptsEdited {
20676        ids: Vec<ExcerptId>,
20677    },
20678    ExcerptsExpanded {
20679        ids: Vec<ExcerptId>,
20680    },
20681    BufferEdited,
20682    Edited {
20683        transaction_id: clock::Lamport,
20684    },
20685    Reparsed(BufferId),
20686    Focused,
20687    FocusedIn,
20688    Blurred,
20689    DirtyChanged,
20690    Saved,
20691    TitleChanged,
20692    DiffBaseChanged,
20693    SelectionsChanged {
20694        local: bool,
20695    },
20696    ScrollPositionChanged {
20697        local: bool,
20698        autoscroll: bool,
20699    },
20700    Closed,
20701    TransactionUndone {
20702        transaction_id: clock::Lamport,
20703    },
20704    TransactionBegun {
20705        transaction_id: clock::Lamport,
20706    },
20707    Reloaded,
20708    CursorShapeChanged,
20709    PushedToNavHistory {
20710        anchor: Anchor,
20711        is_deactivate: bool,
20712    },
20713}
20714
20715impl EventEmitter<EditorEvent> for Editor {}
20716
20717impl Focusable for Editor {
20718    fn focus_handle(&self, _cx: &App) -> FocusHandle {
20719        self.focus_handle.clone()
20720    }
20721}
20722
20723impl Render for Editor {
20724    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
20725        let settings = ThemeSettings::get_global(cx);
20726
20727        let mut text_style = match self.mode {
20728            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
20729                color: cx.theme().colors().editor_foreground,
20730                font_family: settings.ui_font.family.clone(),
20731                font_features: settings.ui_font.features.clone(),
20732                font_fallbacks: settings.ui_font.fallbacks.clone(),
20733                font_size: rems(0.875).into(),
20734                font_weight: settings.ui_font.weight,
20735                line_height: relative(settings.buffer_line_height.value()),
20736                ..Default::default()
20737            },
20738            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
20739                color: cx.theme().colors().editor_foreground,
20740                font_family: settings.buffer_font.family.clone(),
20741                font_features: settings.buffer_font.features.clone(),
20742                font_fallbacks: settings.buffer_font.fallbacks.clone(),
20743                font_size: settings.buffer_font_size(cx).into(),
20744                font_weight: settings.buffer_font.weight,
20745                line_height: relative(settings.buffer_line_height.value()),
20746                ..Default::default()
20747            },
20748        };
20749        if let Some(text_style_refinement) = &self.text_style_refinement {
20750            text_style.refine(text_style_refinement)
20751        }
20752
20753        let background = match self.mode {
20754            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
20755            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
20756            EditorMode::Full { .. } => cx.theme().colors().editor_background,
20757            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
20758        };
20759
20760        EditorElement::new(
20761            &cx.entity(),
20762            EditorStyle {
20763                background,
20764                local_player: cx.theme().players().local(),
20765                text: text_style,
20766                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
20767                syntax: cx.theme().syntax().clone(),
20768                status: cx.theme().status().clone(),
20769                inlay_hints_style: make_inlay_hints_style(cx),
20770                inline_completion_styles: make_suggestion_styles(cx),
20771                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
20772                show_underlines: !self.mode.is_minimap(),
20773            },
20774        )
20775    }
20776}
20777
20778impl EntityInputHandler for Editor {
20779    fn text_for_range(
20780        &mut self,
20781        range_utf16: Range<usize>,
20782        adjusted_range: &mut Option<Range<usize>>,
20783        _: &mut Window,
20784        cx: &mut Context<Self>,
20785    ) -> Option<String> {
20786        let snapshot = self.buffer.read(cx).read(cx);
20787        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
20788        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
20789        if (start.0..end.0) != range_utf16 {
20790            adjusted_range.replace(start.0..end.0);
20791        }
20792        Some(snapshot.text_for_range(start..end).collect())
20793    }
20794
20795    fn selected_text_range(
20796        &mut self,
20797        ignore_disabled_input: bool,
20798        _: &mut Window,
20799        cx: &mut Context<Self>,
20800    ) -> Option<UTF16Selection> {
20801        // Prevent the IME menu from appearing when holding down an alphabetic key
20802        // while input is disabled.
20803        if !ignore_disabled_input && !self.input_enabled {
20804            return None;
20805        }
20806
20807        let selection = self.selections.newest::<OffsetUtf16>(cx);
20808        let range = selection.range();
20809
20810        Some(UTF16Selection {
20811            range: range.start.0..range.end.0,
20812            reversed: selection.reversed,
20813        })
20814    }
20815
20816    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
20817        let snapshot = self.buffer.read(cx).read(cx);
20818        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
20819        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
20820    }
20821
20822    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20823        self.clear_highlights::<InputComposition>(cx);
20824        self.ime_transaction.take();
20825    }
20826
20827    fn replace_text_in_range(
20828        &mut self,
20829        range_utf16: Option<Range<usize>>,
20830        text: &str,
20831        window: &mut Window,
20832        cx: &mut Context<Self>,
20833    ) {
20834        if !self.input_enabled {
20835            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20836            return;
20837        }
20838
20839        self.transact(window, cx, |this, window, cx| {
20840            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
20841                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20842                Some(this.selection_replacement_ranges(range_utf16, cx))
20843            } else {
20844                this.marked_text_ranges(cx)
20845            };
20846
20847            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
20848                let newest_selection_id = this.selections.newest_anchor().id;
20849                this.selections
20850                    .all::<OffsetUtf16>(cx)
20851                    .iter()
20852                    .zip(ranges_to_replace.iter())
20853                    .find_map(|(selection, range)| {
20854                        if selection.id == newest_selection_id {
20855                            Some(
20856                                (range.start.0 as isize - selection.head().0 as isize)
20857                                    ..(range.end.0 as isize - selection.head().0 as isize),
20858                            )
20859                        } else {
20860                            None
20861                        }
20862                    })
20863            });
20864
20865            cx.emit(EditorEvent::InputHandled {
20866                utf16_range_to_replace: range_to_replace,
20867                text: text.into(),
20868            });
20869
20870            if let Some(new_selected_ranges) = new_selected_ranges {
20871                this.change_selections(None, window, cx, |selections| {
20872                    selections.select_ranges(new_selected_ranges)
20873                });
20874                this.backspace(&Default::default(), window, cx);
20875            }
20876
20877            this.handle_input(text, window, cx);
20878        });
20879
20880        if let Some(transaction) = self.ime_transaction {
20881            self.buffer.update(cx, |buffer, cx| {
20882                buffer.group_until_transaction(transaction, cx);
20883            });
20884        }
20885
20886        self.unmark_text(window, cx);
20887    }
20888
20889    fn replace_and_mark_text_in_range(
20890        &mut self,
20891        range_utf16: Option<Range<usize>>,
20892        text: &str,
20893        new_selected_range_utf16: Option<Range<usize>>,
20894        window: &mut Window,
20895        cx: &mut Context<Self>,
20896    ) {
20897        if !self.input_enabled {
20898            return;
20899        }
20900
20901        let transaction = self.transact(window, cx, |this, window, cx| {
20902            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
20903                let snapshot = this.buffer.read(cx).read(cx);
20904                if let Some(relative_range_utf16) = range_utf16.as_ref() {
20905                    for marked_range in &mut marked_ranges {
20906                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
20907                        marked_range.start.0 += relative_range_utf16.start;
20908                        marked_range.start =
20909                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
20910                        marked_range.end =
20911                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
20912                    }
20913                }
20914                Some(marked_ranges)
20915            } else if let Some(range_utf16) = range_utf16 {
20916                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20917                Some(this.selection_replacement_ranges(range_utf16, cx))
20918            } else {
20919                None
20920            };
20921
20922            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
20923                let newest_selection_id = this.selections.newest_anchor().id;
20924                this.selections
20925                    .all::<OffsetUtf16>(cx)
20926                    .iter()
20927                    .zip(ranges_to_replace.iter())
20928                    .find_map(|(selection, range)| {
20929                        if selection.id == newest_selection_id {
20930                            Some(
20931                                (range.start.0 as isize - selection.head().0 as isize)
20932                                    ..(range.end.0 as isize - selection.head().0 as isize),
20933                            )
20934                        } else {
20935                            None
20936                        }
20937                    })
20938            });
20939
20940            cx.emit(EditorEvent::InputHandled {
20941                utf16_range_to_replace: range_to_replace,
20942                text: text.into(),
20943            });
20944
20945            if let Some(ranges) = ranges_to_replace {
20946                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
20947            }
20948
20949            let marked_ranges = {
20950                let snapshot = this.buffer.read(cx).read(cx);
20951                this.selections
20952                    .disjoint_anchors()
20953                    .iter()
20954                    .map(|selection| {
20955                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
20956                    })
20957                    .collect::<Vec<_>>()
20958            };
20959
20960            if text.is_empty() {
20961                this.unmark_text(window, cx);
20962            } else {
20963                this.highlight_text::<InputComposition>(
20964                    marked_ranges.clone(),
20965                    HighlightStyle {
20966                        underline: Some(UnderlineStyle {
20967                            thickness: px(1.),
20968                            color: None,
20969                            wavy: false,
20970                        }),
20971                        ..Default::default()
20972                    },
20973                    cx,
20974                );
20975            }
20976
20977            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
20978            let use_autoclose = this.use_autoclose;
20979            let use_auto_surround = this.use_auto_surround;
20980            this.set_use_autoclose(false);
20981            this.set_use_auto_surround(false);
20982            this.handle_input(text, window, cx);
20983            this.set_use_autoclose(use_autoclose);
20984            this.set_use_auto_surround(use_auto_surround);
20985
20986            if let Some(new_selected_range) = new_selected_range_utf16 {
20987                let snapshot = this.buffer.read(cx).read(cx);
20988                let new_selected_ranges = marked_ranges
20989                    .into_iter()
20990                    .map(|marked_range| {
20991                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
20992                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
20993                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
20994                        snapshot.clip_offset_utf16(new_start, Bias::Left)
20995                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
20996                    })
20997                    .collect::<Vec<_>>();
20998
20999                drop(snapshot);
21000                this.change_selections(None, window, cx, |selections| {
21001                    selections.select_ranges(new_selected_ranges)
21002                });
21003            }
21004        });
21005
21006        self.ime_transaction = self.ime_transaction.or(transaction);
21007        if let Some(transaction) = self.ime_transaction {
21008            self.buffer.update(cx, |buffer, cx| {
21009                buffer.group_until_transaction(transaction, cx);
21010            });
21011        }
21012
21013        if self.text_highlights::<InputComposition>(cx).is_none() {
21014            self.ime_transaction.take();
21015        }
21016    }
21017
21018    fn bounds_for_range(
21019        &mut self,
21020        range_utf16: Range<usize>,
21021        element_bounds: gpui::Bounds<Pixels>,
21022        window: &mut Window,
21023        cx: &mut Context<Self>,
21024    ) -> Option<gpui::Bounds<Pixels>> {
21025        let text_layout_details = self.text_layout_details(window);
21026        let gpui::Size {
21027            width: em_width,
21028            height: line_height,
21029        } = self.character_size(window);
21030
21031        let snapshot = self.snapshot(window, cx);
21032        let scroll_position = snapshot.scroll_position();
21033        let scroll_left = scroll_position.x * em_width;
21034
21035        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
21036        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
21037            + self.gutter_dimensions.width
21038            + self.gutter_dimensions.margin;
21039        let y = line_height * (start.row().as_f32() - scroll_position.y);
21040
21041        Some(Bounds {
21042            origin: element_bounds.origin + point(x, y),
21043            size: size(em_width, line_height),
21044        })
21045    }
21046
21047    fn character_index_for_point(
21048        &mut self,
21049        point: gpui::Point<Pixels>,
21050        _window: &mut Window,
21051        _cx: &mut Context<Self>,
21052    ) -> Option<usize> {
21053        let position_map = self.last_position_map.as_ref()?;
21054        if !position_map.text_hitbox.contains(&point) {
21055            return None;
21056        }
21057        let display_point = position_map.point_for_position(point).previous_valid;
21058        let anchor = position_map
21059            .snapshot
21060            .display_point_to_anchor(display_point, Bias::Left);
21061        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
21062        Some(utf16_offset.0)
21063    }
21064}
21065
21066trait SelectionExt {
21067    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
21068    fn spanned_rows(
21069        &self,
21070        include_end_if_at_line_start: bool,
21071        map: &DisplaySnapshot,
21072    ) -> Range<MultiBufferRow>;
21073}
21074
21075impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
21076    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
21077        let start = self
21078            .start
21079            .to_point(&map.buffer_snapshot)
21080            .to_display_point(map);
21081        let end = self
21082            .end
21083            .to_point(&map.buffer_snapshot)
21084            .to_display_point(map);
21085        if self.reversed {
21086            end..start
21087        } else {
21088            start..end
21089        }
21090    }
21091
21092    fn spanned_rows(
21093        &self,
21094        include_end_if_at_line_start: bool,
21095        map: &DisplaySnapshot,
21096    ) -> Range<MultiBufferRow> {
21097        let start = self.start.to_point(&map.buffer_snapshot);
21098        let mut end = self.end.to_point(&map.buffer_snapshot);
21099        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
21100            end.row -= 1;
21101        }
21102
21103        let buffer_start = map.prev_line_boundary(start).0;
21104        let buffer_end = map.next_line_boundary(end).0;
21105        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
21106    }
21107}
21108
21109impl<T: InvalidationRegion> InvalidationStack<T> {
21110    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
21111    where
21112        S: Clone + ToOffset,
21113    {
21114        while let Some(region) = self.last() {
21115            let all_selections_inside_invalidation_ranges =
21116                if selections.len() == region.ranges().len() {
21117                    selections
21118                        .iter()
21119                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
21120                        .all(|(selection, invalidation_range)| {
21121                            let head = selection.head().to_offset(buffer);
21122                            invalidation_range.start <= head && invalidation_range.end >= head
21123                        })
21124                } else {
21125                    false
21126                };
21127
21128            if all_selections_inside_invalidation_ranges {
21129                break;
21130            } else {
21131                self.pop();
21132            }
21133        }
21134    }
21135}
21136
21137impl<T> Default for InvalidationStack<T> {
21138    fn default() -> Self {
21139        Self(Default::default())
21140    }
21141}
21142
21143impl<T> Deref for InvalidationStack<T> {
21144    type Target = Vec<T>;
21145
21146    fn deref(&self) -> &Self::Target {
21147        &self.0
21148    }
21149}
21150
21151impl<T> DerefMut for InvalidationStack<T> {
21152    fn deref_mut(&mut self) -> &mut Self::Target {
21153        &mut self.0
21154    }
21155}
21156
21157impl InvalidationRegion for SnippetState {
21158    fn ranges(&self) -> &[Range<Anchor>] {
21159        &self.ranges[self.active_index]
21160    }
21161}
21162
21163fn inline_completion_edit_text(
21164    current_snapshot: &BufferSnapshot,
21165    edits: &[(Range<Anchor>, String)],
21166    edit_preview: &EditPreview,
21167    include_deletions: bool,
21168    cx: &App,
21169) -> HighlightedText {
21170    let edits = edits
21171        .iter()
21172        .map(|(anchor, text)| {
21173            (
21174                anchor.start.text_anchor..anchor.end.text_anchor,
21175                text.clone(),
21176            )
21177        })
21178        .collect::<Vec<_>>();
21179
21180    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
21181}
21182
21183pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
21184    match severity {
21185        lsp::DiagnosticSeverity::ERROR => colors.error,
21186        lsp::DiagnosticSeverity::WARNING => colors.warning,
21187        lsp::DiagnosticSeverity::INFORMATION => colors.info,
21188        lsp::DiagnosticSeverity::HINT => colors.info,
21189        _ => colors.ignored,
21190    }
21191}
21192
21193pub fn styled_runs_for_code_label<'a>(
21194    label: &'a CodeLabel,
21195    syntax_theme: &'a theme::SyntaxTheme,
21196) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
21197    let fade_out = HighlightStyle {
21198        fade_out: Some(0.35),
21199        ..Default::default()
21200    };
21201
21202    let mut prev_end = label.filter_range.end;
21203    label
21204        .runs
21205        .iter()
21206        .enumerate()
21207        .flat_map(move |(ix, (range, highlight_id))| {
21208            let style = if let Some(style) = highlight_id.style(syntax_theme) {
21209                style
21210            } else {
21211                return Default::default();
21212            };
21213            let mut muted_style = style;
21214            muted_style.highlight(fade_out);
21215
21216            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
21217            if range.start >= label.filter_range.end {
21218                if range.start > prev_end {
21219                    runs.push((prev_end..range.start, fade_out));
21220                }
21221                runs.push((range.clone(), muted_style));
21222            } else if range.end <= label.filter_range.end {
21223                runs.push((range.clone(), style));
21224            } else {
21225                runs.push((range.start..label.filter_range.end, style));
21226                runs.push((label.filter_range.end..range.end, muted_style));
21227            }
21228            prev_end = cmp::max(prev_end, range.end);
21229
21230            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
21231                runs.push((prev_end..label.text.len(), fade_out));
21232            }
21233
21234            runs
21235        })
21236}
21237
21238pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
21239    let mut prev_index = 0;
21240    let mut prev_codepoint: Option<char> = None;
21241    text.char_indices()
21242        .chain([(text.len(), '\0')])
21243        .filter_map(move |(index, codepoint)| {
21244            let prev_codepoint = prev_codepoint.replace(codepoint)?;
21245            let is_boundary = index == text.len()
21246                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
21247                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
21248            if is_boundary {
21249                let chunk = &text[prev_index..index];
21250                prev_index = index;
21251                Some(chunk)
21252            } else {
21253                None
21254            }
21255        })
21256}
21257
21258pub trait RangeToAnchorExt: Sized {
21259    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
21260
21261    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
21262        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
21263        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
21264    }
21265}
21266
21267impl<T: ToOffset> RangeToAnchorExt for Range<T> {
21268    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
21269        let start_offset = self.start.to_offset(snapshot);
21270        let end_offset = self.end.to_offset(snapshot);
21271        if start_offset == end_offset {
21272            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
21273        } else {
21274            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
21275        }
21276    }
21277}
21278
21279pub trait RowExt {
21280    fn as_f32(&self) -> f32;
21281
21282    fn next_row(&self) -> Self;
21283
21284    fn previous_row(&self) -> Self;
21285
21286    fn minus(&self, other: Self) -> u32;
21287}
21288
21289impl RowExt for DisplayRow {
21290    fn as_f32(&self) -> f32 {
21291        self.0 as f32
21292    }
21293
21294    fn next_row(&self) -> Self {
21295        Self(self.0 + 1)
21296    }
21297
21298    fn previous_row(&self) -> Self {
21299        Self(self.0.saturating_sub(1))
21300    }
21301
21302    fn minus(&self, other: Self) -> u32 {
21303        self.0 - other.0
21304    }
21305}
21306
21307impl RowExt for MultiBufferRow {
21308    fn as_f32(&self) -> f32 {
21309        self.0 as f32
21310    }
21311
21312    fn next_row(&self) -> Self {
21313        Self(self.0 + 1)
21314    }
21315
21316    fn previous_row(&self) -> Self {
21317        Self(self.0.saturating_sub(1))
21318    }
21319
21320    fn minus(&self, other: Self) -> u32 {
21321        self.0 - other.0
21322    }
21323}
21324
21325trait RowRangeExt {
21326    type Row;
21327
21328    fn len(&self) -> usize;
21329
21330    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
21331}
21332
21333impl RowRangeExt for Range<MultiBufferRow> {
21334    type Row = MultiBufferRow;
21335
21336    fn len(&self) -> usize {
21337        (self.end.0 - self.start.0) as usize
21338    }
21339
21340    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
21341        (self.start.0..self.end.0).map(MultiBufferRow)
21342    }
21343}
21344
21345impl RowRangeExt for Range<DisplayRow> {
21346    type Row = DisplayRow;
21347
21348    fn len(&self) -> usize {
21349        (self.end.0 - self.start.0) as usize
21350    }
21351
21352    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
21353        (self.start.0..self.end.0).map(DisplayRow)
21354    }
21355}
21356
21357/// If select range has more than one line, we
21358/// just point the cursor to range.start.
21359fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
21360    if range.start.row == range.end.row {
21361        range
21362    } else {
21363        range.start..range.start
21364    }
21365}
21366pub struct KillRing(ClipboardItem);
21367impl Global for KillRing {}
21368
21369const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
21370
21371enum BreakpointPromptEditAction {
21372    Log,
21373    Condition,
21374    HitCondition,
21375}
21376
21377struct BreakpointPromptEditor {
21378    pub(crate) prompt: Entity<Editor>,
21379    editor: WeakEntity<Editor>,
21380    breakpoint_anchor: Anchor,
21381    breakpoint: Breakpoint,
21382    edit_action: BreakpointPromptEditAction,
21383    block_ids: HashSet<CustomBlockId>,
21384    editor_margins: Arc<Mutex<EditorMargins>>,
21385    _subscriptions: Vec<Subscription>,
21386}
21387
21388impl BreakpointPromptEditor {
21389    const MAX_LINES: u8 = 4;
21390
21391    fn new(
21392        editor: WeakEntity<Editor>,
21393        breakpoint_anchor: Anchor,
21394        breakpoint: Breakpoint,
21395        edit_action: BreakpointPromptEditAction,
21396        window: &mut Window,
21397        cx: &mut Context<Self>,
21398    ) -> Self {
21399        let base_text = match edit_action {
21400            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
21401            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
21402            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
21403        }
21404        .map(|msg| msg.to_string())
21405        .unwrap_or_default();
21406
21407        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
21408        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
21409
21410        let prompt = cx.new(|cx| {
21411            let mut prompt = Editor::new(
21412                EditorMode::AutoHeight {
21413                    max_lines: Self::MAX_LINES as usize,
21414                },
21415                buffer,
21416                None,
21417                window,
21418                cx,
21419            );
21420            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
21421            prompt.set_show_cursor_when_unfocused(false, cx);
21422            prompt.set_placeholder_text(
21423                match edit_action {
21424                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
21425                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
21426                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
21427                },
21428                cx,
21429            );
21430
21431            prompt
21432        });
21433
21434        Self {
21435            prompt,
21436            editor,
21437            breakpoint_anchor,
21438            breakpoint,
21439            edit_action,
21440            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
21441            block_ids: Default::default(),
21442            _subscriptions: vec![],
21443        }
21444    }
21445
21446    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
21447        self.block_ids.extend(block_ids)
21448    }
21449
21450    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
21451        if let Some(editor) = self.editor.upgrade() {
21452            let message = self
21453                .prompt
21454                .read(cx)
21455                .buffer
21456                .read(cx)
21457                .as_singleton()
21458                .expect("A multi buffer in breakpoint prompt isn't possible")
21459                .read(cx)
21460                .as_rope()
21461                .to_string();
21462
21463            editor.update(cx, |editor, cx| {
21464                editor.edit_breakpoint_at_anchor(
21465                    self.breakpoint_anchor,
21466                    self.breakpoint.clone(),
21467                    match self.edit_action {
21468                        BreakpointPromptEditAction::Log => {
21469                            BreakpointEditAction::EditLogMessage(message.into())
21470                        }
21471                        BreakpointPromptEditAction::Condition => {
21472                            BreakpointEditAction::EditCondition(message.into())
21473                        }
21474                        BreakpointPromptEditAction::HitCondition => {
21475                            BreakpointEditAction::EditHitCondition(message.into())
21476                        }
21477                    },
21478                    cx,
21479                );
21480
21481                editor.remove_blocks(self.block_ids.clone(), None, cx);
21482                cx.focus_self(window);
21483            });
21484        }
21485    }
21486
21487    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
21488        self.editor
21489            .update(cx, |editor, cx| {
21490                editor.remove_blocks(self.block_ids.clone(), None, cx);
21491                window.focus(&editor.focus_handle);
21492            })
21493            .log_err();
21494    }
21495
21496    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
21497        let settings = ThemeSettings::get_global(cx);
21498        let text_style = TextStyle {
21499            color: if self.prompt.read(cx).read_only(cx) {
21500                cx.theme().colors().text_disabled
21501            } else {
21502                cx.theme().colors().text
21503            },
21504            font_family: settings.buffer_font.family.clone(),
21505            font_fallbacks: settings.buffer_font.fallbacks.clone(),
21506            font_size: settings.buffer_font_size(cx).into(),
21507            font_weight: settings.buffer_font.weight,
21508            line_height: relative(settings.buffer_line_height.value()),
21509            ..Default::default()
21510        };
21511        EditorElement::new(
21512            &self.prompt,
21513            EditorStyle {
21514                background: cx.theme().colors().editor_background,
21515                local_player: cx.theme().players().local(),
21516                text: text_style,
21517                ..Default::default()
21518            },
21519        )
21520    }
21521}
21522
21523impl Render for BreakpointPromptEditor {
21524    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21525        let editor_margins = *self.editor_margins.lock();
21526        let gutter_dimensions = editor_margins.gutter;
21527        h_flex()
21528            .key_context("Editor")
21529            .bg(cx.theme().colors().editor_background)
21530            .border_y_1()
21531            .border_color(cx.theme().status().info_border)
21532            .size_full()
21533            .py(window.line_height() / 2.5)
21534            .on_action(cx.listener(Self::confirm))
21535            .on_action(cx.listener(Self::cancel))
21536            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
21537            .child(div().flex_1().child(self.render_prompt_editor(cx)))
21538    }
21539}
21540
21541impl Focusable for BreakpointPromptEditor {
21542    fn focus_handle(&self, cx: &App) -> FocusHandle {
21543        self.prompt.focus_handle(cx)
21544    }
21545}
21546
21547fn all_edits_insertions_or_deletions(
21548    edits: &Vec<(Range<Anchor>, String)>,
21549    snapshot: &MultiBufferSnapshot,
21550) -> bool {
21551    let mut all_insertions = true;
21552    let mut all_deletions = true;
21553
21554    for (range, new_text) in edits.iter() {
21555        let range_is_empty = range.to_offset(&snapshot).is_empty();
21556        let text_is_empty = new_text.is_empty();
21557
21558        if range_is_empty != text_is_empty {
21559            if range_is_empty {
21560                all_deletions = false;
21561            } else {
21562                all_insertions = false;
21563            }
21564        } else {
21565            return false;
21566        }
21567
21568        if !all_insertions && !all_deletions {
21569            return false;
21570        }
21571    }
21572    all_insertions || all_deletions
21573}
21574
21575struct MissingEditPredictionKeybindingTooltip;
21576
21577impl Render for MissingEditPredictionKeybindingTooltip {
21578    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21579        ui::tooltip_container(window, cx, |container, _, cx| {
21580            container
21581                .flex_shrink_0()
21582                .max_w_80()
21583                .min_h(rems_from_px(124.))
21584                .justify_between()
21585                .child(
21586                    v_flex()
21587                        .flex_1()
21588                        .text_ui_sm(cx)
21589                        .child(Label::new("Conflict with Accept Keybinding"))
21590                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
21591                )
21592                .child(
21593                    h_flex()
21594                        .pb_1()
21595                        .gap_1()
21596                        .items_end()
21597                        .w_full()
21598                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
21599                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
21600                        }))
21601                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
21602                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
21603                        })),
21604                )
21605        })
21606    }
21607}
21608
21609#[derive(Debug, Clone, Copy, PartialEq)]
21610pub struct LineHighlight {
21611    pub background: Background,
21612    pub border: Option<gpui::Hsla>,
21613    pub include_gutter: bool,
21614    pub type_id: Option<TypeId>,
21615}
21616
21617fn render_diff_hunk_controls(
21618    row: u32,
21619    status: &DiffHunkStatus,
21620    hunk_range: Range<Anchor>,
21621    is_created_file: bool,
21622    line_height: Pixels,
21623    editor: &Entity<Editor>,
21624    _window: &mut Window,
21625    cx: &mut App,
21626) -> AnyElement {
21627    h_flex()
21628        .h(line_height)
21629        .mr_1()
21630        .gap_1()
21631        .px_0p5()
21632        .pb_1()
21633        .border_x_1()
21634        .border_b_1()
21635        .border_color(cx.theme().colors().border_variant)
21636        .rounded_b_lg()
21637        .bg(cx.theme().colors().editor_background)
21638        .gap_1()
21639        .occlude()
21640        .shadow_md()
21641        .child(if status.has_secondary_hunk() {
21642            Button::new(("stage", row as u64), "Stage")
21643                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21644                .tooltip({
21645                    let focus_handle = editor.focus_handle(cx);
21646                    move |window, cx| {
21647                        Tooltip::for_action_in(
21648                            "Stage Hunk",
21649                            &::git::ToggleStaged,
21650                            &focus_handle,
21651                            window,
21652                            cx,
21653                        )
21654                    }
21655                })
21656                .on_click({
21657                    let editor = editor.clone();
21658                    move |_event, _window, cx| {
21659                        editor.update(cx, |editor, cx| {
21660                            editor.stage_or_unstage_diff_hunks(
21661                                true,
21662                                vec![hunk_range.start..hunk_range.start],
21663                                cx,
21664                            );
21665                        });
21666                    }
21667                })
21668        } else {
21669            Button::new(("unstage", row as u64), "Unstage")
21670                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21671                .tooltip({
21672                    let focus_handle = editor.focus_handle(cx);
21673                    move |window, cx| {
21674                        Tooltip::for_action_in(
21675                            "Unstage Hunk",
21676                            &::git::ToggleStaged,
21677                            &focus_handle,
21678                            window,
21679                            cx,
21680                        )
21681                    }
21682                })
21683                .on_click({
21684                    let editor = editor.clone();
21685                    move |_event, _window, cx| {
21686                        editor.update(cx, |editor, cx| {
21687                            editor.stage_or_unstage_diff_hunks(
21688                                false,
21689                                vec![hunk_range.start..hunk_range.start],
21690                                cx,
21691                            );
21692                        });
21693                    }
21694                })
21695        })
21696        .child(
21697            Button::new(("restore", row as u64), "Restore")
21698                .tooltip({
21699                    let focus_handle = editor.focus_handle(cx);
21700                    move |window, cx| {
21701                        Tooltip::for_action_in(
21702                            "Restore Hunk",
21703                            &::git::Restore,
21704                            &focus_handle,
21705                            window,
21706                            cx,
21707                        )
21708                    }
21709                })
21710                .on_click({
21711                    let editor = editor.clone();
21712                    move |_event, window, cx| {
21713                        editor.update(cx, |editor, cx| {
21714                            let snapshot = editor.snapshot(window, cx);
21715                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
21716                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
21717                        });
21718                    }
21719                })
21720                .disabled(is_created_file),
21721        )
21722        .when(
21723            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
21724            |el| {
21725                el.child(
21726                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
21727                        .shape(IconButtonShape::Square)
21728                        .icon_size(IconSize::Small)
21729                        // .disabled(!has_multiple_hunks)
21730                        .tooltip({
21731                            let focus_handle = editor.focus_handle(cx);
21732                            move |window, cx| {
21733                                Tooltip::for_action_in(
21734                                    "Next Hunk",
21735                                    &GoToHunk,
21736                                    &focus_handle,
21737                                    window,
21738                                    cx,
21739                                )
21740                            }
21741                        })
21742                        .on_click({
21743                            let editor = editor.clone();
21744                            move |_event, window, cx| {
21745                                editor.update(cx, |editor, cx| {
21746                                    let snapshot = editor.snapshot(window, cx);
21747                                    let position =
21748                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
21749                                    editor.go_to_hunk_before_or_after_position(
21750                                        &snapshot,
21751                                        position,
21752                                        Direction::Next,
21753                                        window,
21754                                        cx,
21755                                    );
21756                                    editor.expand_selected_diff_hunks(cx);
21757                                });
21758                            }
21759                        }),
21760                )
21761                .child(
21762                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
21763                        .shape(IconButtonShape::Square)
21764                        .icon_size(IconSize::Small)
21765                        // .disabled(!has_multiple_hunks)
21766                        .tooltip({
21767                            let focus_handle = editor.focus_handle(cx);
21768                            move |window, cx| {
21769                                Tooltip::for_action_in(
21770                                    "Previous Hunk",
21771                                    &GoToPreviousHunk,
21772                                    &focus_handle,
21773                                    window,
21774                                    cx,
21775                                )
21776                            }
21777                        })
21778                        .on_click({
21779                            let editor = editor.clone();
21780                            move |_event, window, cx| {
21781                                editor.update(cx, |editor, cx| {
21782                                    let snapshot = editor.snapshot(window, cx);
21783                                    let point =
21784                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
21785                                    editor.go_to_hunk_before_or_after_position(
21786                                        &snapshot,
21787                                        point,
21788                                        Direction::Prev,
21789                                        window,
21790                                        cx,
21791                                    );
21792                                    editor.expand_selected_diff_hunks(cx);
21793                                });
21794                            }
21795                        }),
21796                )
21797            },
21798        )
21799        .into_any_element()
21800}