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::ReplicaId;
   60use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   61use convert_case::{Case, Casing};
   62use display_map::*;
   63pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   64use editor_settings::GoToDefinitionFallback;
   65pub use editor_settings::{
   66    CurrentLineHighlight, EditorSettings, HideMouseMode, ScrollBeyondLastLine, SearchSettings,
   67    ShowScrollbar,
   68};
   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::Restore;
   82use code_context_menus::{
   83    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   84    CompletionsMenu, ContextMenuOrigin,
   85};
   86use git::blame::{GitBlame, GlobalBlameRenderer};
   87use gpui::{
   88    Action, Animation, AnimationExt, AnyElement, AnyWeakEntity, App, AppContext,
   89    AsyncWindowContext, AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry,
   90    ClipboardItem, Context, DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter,
   91    FocusHandle, FocusOutEvent, Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla,
   92    KeyContext, Modifiers, MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render,
   93    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   94    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   95    div, impl_actions, point, prelude::*, pulsating_between, px, relative, size,
   96};
   97use highlight_matching_bracket::refresh_matching_bracket_highlights;
   98use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
   99pub use hover_popover::hover_markdown_style;
  100use hover_popover::{HoverState, hide_hover};
  101use indent_guides::ActiveIndentGuidesState;
  102use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  103pub use inline_completion::Direction;
  104use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  105pub use items::MAX_TAB_TITLE_LEN;
  106use itertools::Itertools;
  107use language::{
  108    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  109    CursorShape, DiagnosticEntry, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText,
  110    IndentKind, IndentSize, Language, OffsetRangeExt, Point, Selection, SelectionGoal, TextObject,
  111    TransactionId, TreeSitterOptions, WordsQuery,
  112    language_settings::{
  113        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  114        all_language_settings, language_settings,
  115    },
  116    point_from_lsp, text_diff_with_options,
  117};
  118use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  119use linked_editing_ranges::refresh_linked_ranges;
  120use mouse_context_menu::MouseContextMenu;
  121use persistence::DB;
  122use project::{
  123    ProjectPath,
  124    debugger::breakpoint_store::{
  125        BreakpointEditAction, BreakpointState, BreakpointStore, BreakpointStoreEvent,
  126    },
  127};
  128
  129pub use git::blame::BlameRenderer;
  130pub use proposed_changes_editor::{
  131    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  132};
  133use smallvec::smallvec;
  134use std::{cell::OnceCell, iter::Peekable};
  135use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  136
  137pub use lsp::CompletionContext;
  138use lsp::{
  139    CodeActionKind, CompletionItemKind, CompletionTriggerKind, DiagnosticSeverity,
  140    InsertTextFormat, InsertTextMode, LanguageServerId, LanguageServerName,
  141};
  142
  143use language::BufferSnapshot;
  144pub use lsp_ext::lsp_tasks;
  145use movement::TextLayoutDetails;
  146pub use multi_buffer::{
  147    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  148    RowInfo, ToOffset, ToPoint,
  149};
  150use multi_buffer::{
  151    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  152    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  153};
  154use parking_lot::Mutex;
  155use project::{
  156    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  157    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  158    TaskSourceKind,
  159    debugger::breakpoint_store::Breakpoint,
  160    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  161    project_settings::{GitGutterSetting, ProjectSettings},
  162};
  163use rand::prelude::*;
  164use rpc::{ErrorExt, proto::*};
  165use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  166use selections_collection::{
  167    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  168};
  169use serde::{Deserialize, Serialize};
  170use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  171use smallvec::SmallVec;
  172use snippet::Snippet;
  173use std::sync::Arc;
  174use std::{
  175    any::TypeId,
  176    borrow::Cow,
  177    cell::RefCell,
  178    cmp::{self, Ordering, Reverse},
  179    mem,
  180    num::NonZeroU32,
  181    ops::{ControlFlow, Deref, DerefMut, Not as _, Range, RangeInclusive},
  182    path::{Path, PathBuf},
  183    rc::Rc,
  184    time::{Duration, Instant},
  185};
  186pub use sum_tree::Bias;
  187use sum_tree::TreeMap;
  188use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  189use theme::{
  190    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, ThemeColors, ThemeSettings,
  191    observe_buffer_font_size_adjustment,
  192};
  193use ui::{
  194    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  195    IconSize, Key, Tooltip, h_flex, prelude::*,
  196};
  197use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  198use workspace::{
  199    Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  200    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  201    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  202    item::{ItemHandle, PreviewTabsSettings},
  203    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  204    searchable::SearchEvent,
  205};
  206
  207use crate::hover_links::{find_url, find_url_from_range};
  208use crate::signature_help::{SignatureHelpHiddenBy, SignatureHelpState};
  209
  210pub const FILE_HEADER_HEIGHT: u32 = 2;
  211pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  212pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  213const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  214const MAX_LINE_LEN: usize = 1024;
  215const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  216const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  217pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  218#[doc(hidden)]
  219pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  220const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  221
  222pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  223pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  224pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  225
  226pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  227pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  228pub(crate) const MIN_LINE_NUMBER_DIGITS: u32 = 4;
  229
  230pub type RenderDiffHunkControlsFn = Arc<
  231    dyn Fn(
  232        u32,
  233        &DiffHunkStatus,
  234        Range<Anchor>,
  235        bool,
  236        Pixels,
  237        &Entity<Editor>,
  238        &mut Window,
  239        &mut App,
  240    ) -> AnyElement,
  241>;
  242
  243const COLUMNAR_SELECTION_MODIFIERS: Modifiers = Modifiers {
  244    alt: true,
  245    shift: true,
  246    control: false,
  247    platform: false,
  248    function: false,
  249};
  250
  251#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  252pub enum InlayId {
  253    InlineCompletion(usize),
  254    Hint(usize),
  255}
  256
  257impl InlayId {
  258    fn id(&self) -> usize {
  259        match self {
  260            Self::InlineCompletion(id) => *id,
  261            Self::Hint(id) => *id,
  262        }
  263    }
  264}
  265
  266pub enum DebugCurrentRowHighlight {}
  267enum DocumentHighlightRead {}
  268enum DocumentHighlightWrite {}
  269enum InputComposition {}
  270enum SelectedTextHighlight {}
  271
  272#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  273pub enum Navigated {
  274    Yes,
  275    No,
  276}
  277
  278impl Navigated {
  279    pub fn from_bool(yes: bool) -> Navigated {
  280        if yes { Navigated::Yes } else { Navigated::No }
  281    }
  282}
  283
  284#[derive(Debug, Clone, PartialEq, Eq)]
  285enum DisplayDiffHunk {
  286    Folded {
  287        display_row: DisplayRow,
  288    },
  289    Unfolded {
  290        is_created_file: bool,
  291        diff_base_byte_range: Range<usize>,
  292        display_row_range: Range<DisplayRow>,
  293        multi_buffer_range: Range<Anchor>,
  294        status: DiffHunkStatus,
  295    },
  296}
  297
  298pub enum HideMouseCursorOrigin {
  299    TypingAction,
  300    MovementAction,
  301}
  302
  303pub fn init_settings(cx: &mut App) {
  304    EditorSettings::register(cx);
  305}
  306
  307pub fn init(cx: &mut App) {
  308    init_settings(cx);
  309
  310    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  311
  312    workspace::register_project_item::<Editor>(cx);
  313    workspace::FollowableViewRegistry::register::<Editor>(cx);
  314    workspace::register_serializable_item::<Editor>(cx);
  315
  316    cx.observe_new(
  317        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  318            workspace.register_action(Editor::new_file);
  319            workspace.register_action(Editor::new_file_vertical);
  320            workspace.register_action(Editor::new_file_horizontal);
  321            workspace.register_action(Editor::cancel_language_server_work);
  322        },
  323    )
  324    .detach();
  325
  326    cx.on_action(move |_: &workspace::NewFile, cx| {
  327        let app_state = workspace::AppState::global(cx);
  328        if let Some(app_state) = app_state.upgrade() {
  329            workspace::open_new(
  330                Default::default(),
  331                app_state,
  332                cx,
  333                |workspace, window, cx| {
  334                    Editor::new_file(workspace, &Default::default(), window, cx)
  335                },
  336            )
  337            .detach();
  338        }
  339    });
  340    cx.on_action(move |_: &workspace::NewWindow, cx| {
  341        let app_state = workspace::AppState::global(cx);
  342        if let Some(app_state) = app_state.upgrade() {
  343            workspace::open_new(
  344                Default::default(),
  345                app_state,
  346                cx,
  347                |workspace, window, cx| {
  348                    cx.activate(true);
  349                    Editor::new_file(workspace, &Default::default(), window, cx)
  350                },
  351            )
  352            .detach();
  353        }
  354    });
  355}
  356
  357pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  358    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  359}
  360
  361pub trait DiagnosticRenderer {
  362    fn render_group(
  363        &self,
  364        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  365        buffer_id: BufferId,
  366        snapshot: EditorSnapshot,
  367        editor: WeakEntity<Editor>,
  368        cx: &mut App,
  369    ) -> Vec<BlockProperties<Anchor>>;
  370}
  371
  372pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  373
  374impl gpui::Global for GlobalDiagnosticRenderer {}
  375pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  376    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  377}
  378
  379pub struct SearchWithinRange;
  380
  381trait InvalidationRegion {
  382    fn ranges(&self) -> &[Range<Anchor>];
  383}
  384
  385#[derive(Clone, Debug, PartialEq)]
  386pub enum SelectPhase {
  387    Begin {
  388        position: DisplayPoint,
  389        add: bool,
  390        click_count: usize,
  391    },
  392    BeginColumnar {
  393        position: DisplayPoint,
  394        reset: bool,
  395        goal_column: u32,
  396    },
  397    Extend {
  398        position: DisplayPoint,
  399        click_count: usize,
  400    },
  401    Update {
  402        position: DisplayPoint,
  403        goal_column: u32,
  404        scroll_delta: gpui::Point<f32>,
  405    },
  406    End,
  407}
  408
  409#[derive(Clone, Debug)]
  410pub enum SelectMode {
  411    Character,
  412    Word(Range<Anchor>),
  413    Line(Range<Anchor>),
  414    All,
  415}
  416
  417#[derive(Copy, Clone, PartialEq, Eq, Debug)]
  418pub enum EditorMode {
  419    SingleLine {
  420        auto_width: bool,
  421    },
  422    AutoHeight {
  423        max_lines: usize,
  424    },
  425    Full {
  426        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  427        scale_ui_elements_with_buffer_font_size: bool,
  428        /// When set to `true`, the editor will render a background for the active line.
  429        show_active_line_background: bool,
  430        /// When set to `true`, the editor's height will be determined by its content.
  431        sized_by_content: bool,
  432    },
  433}
  434
  435impl EditorMode {
  436    pub fn full() -> Self {
  437        Self::Full {
  438            scale_ui_elements_with_buffer_font_size: true,
  439            show_active_line_background: true,
  440            sized_by_content: false,
  441        }
  442    }
  443
  444    pub fn is_full(&self) -> bool {
  445        matches!(self, Self::Full { .. })
  446    }
  447}
  448
  449#[derive(Copy, Clone, Debug)]
  450pub enum SoftWrap {
  451    /// Prefer not to wrap at all.
  452    ///
  453    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  454    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  455    GitDiff,
  456    /// Prefer a single line generally, unless an overly long line is encountered.
  457    None,
  458    /// Soft wrap lines that exceed the editor width.
  459    EditorWidth,
  460    /// Soft wrap lines at the preferred line length.
  461    Column(u32),
  462    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  463    Bounded(u32),
  464}
  465
  466#[derive(Clone)]
  467pub struct EditorStyle {
  468    pub background: Hsla,
  469    pub local_player: PlayerColor,
  470    pub text: TextStyle,
  471    pub scrollbar_width: Pixels,
  472    pub syntax: Arc<SyntaxTheme>,
  473    pub status: StatusColors,
  474    pub inlay_hints_style: HighlightStyle,
  475    pub inline_completion_styles: InlineCompletionStyles,
  476    pub unnecessary_code_fade: f32,
  477}
  478
  479impl Default for EditorStyle {
  480    fn default() -> Self {
  481        Self {
  482            background: Hsla::default(),
  483            local_player: PlayerColor::default(),
  484            text: TextStyle::default(),
  485            scrollbar_width: Pixels::default(),
  486            syntax: Default::default(),
  487            // HACK: Status colors don't have a real default.
  488            // We should look into removing the status colors from the editor
  489            // style and retrieve them directly from the theme.
  490            status: StatusColors::dark(),
  491            inlay_hints_style: HighlightStyle::default(),
  492            inline_completion_styles: InlineCompletionStyles {
  493                insertion: HighlightStyle::default(),
  494                whitespace: HighlightStyle::default(),
  495            },
  496            unnecessary_code_fade: Default::default(),
  497        }
  498    }
  499}
  500
  501pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  502    let show_background = language_settings::language_settings(None, None, cx)
  503        .inlay_hints
  504        .show_background;
  505
  506    HighlightStyle {
  507        color: Some(cx.theme().status().hint),
  508        background_color: show_background.then(|| cx.theme().status().hint_background),
  509        ..HighlightStyle::default()
  510    }
  511}
  512
  513pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  514    InlineCompletionStyles {
  515        insertion: HighlightStyle {
  516            color: Some(cx.theme().status().predictive),
  517            ..HighlightStyle::default()
  518        },
  519        whitespace: HighlightStyle {
  520            background_color: Some(cx.theme().status().created_background),
  521            ..HighlightStyle::default()
  522        },
  523    }
  524}
  525
  526type CompletionId = usize;
  527
  528pub(crate) enum EditDisplayMode {
  529    TabAccept,
  530    DiffPopover,
  531    Inline,
  532}
  533
  534enum InlineCompletion {
  535    Edit {
  536        edits: Vec<(Range<Anchor>, String)>,
  537        edit_preview: Option<EditPreview>,
  538        display_mode: EditDisplayMode,
  539        snapshot: BufferSnapshot,
  540    },
  541    Move {
  542        target: Anchor,
  543        snapshot: BufferSnapshot,
  544    },
  545}
  546
  547struct InlineCompletionState {
  548    inlay_ids: Vec<InlayId>,
  549    completion: InlineCompletion,
  550    completion_id: Option<SharedString>,
  551    invalidation_range: Range<Anchor>,
  552}
  553
  554enum EditPredictionSettings {
  555    Disabled,
  556    Enabled {
  557        show_in_menu: bool,
  558        preview_requires_modifier: bool,
  559    },
  560}
  561
  562enum InlineCompletionHighlight {}
  563
  564#[derive(Debug, Clone)]
  565struct InlineDiagnostic {
  566    message: SharedString,
  567    group_id: usize,
  568    is_primary: bool,
  569    start: Point,
  570    severity: DiagnosticSeverity,
  571}
  572
  573pub enum MenuInlineCompletionsPolicy {
  574    Never,
  575    ByProvider,
  576}
  577
  578pub enum EditPredictionPreview {
  579    /// Modifier is not pressed
  580    Inactive { released_too_fast: bool },
  581    /// Modifier pressed
  582    Active {
  583        since: Instant,
  584        previous_scroll_position: Option<ScrollAnchor>,
  585    },
  586}
  587
  588impl EditPredictionPreview {
  589    pub fn released_too_fast(&self) -> bool {
  590        match self {
  591            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  592            EditPredictionPreview::Active { .. } => false,
  593        }
  594    }
  595
  596    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  597        if let EditPredictionPreview::Active {
  598            previous_scroll_position,
  599            ..
  600        } = self
  601        {
  602            *previous_scroll_position = scroll_position;
  603        }
  604    }
  605}
  606
  607pub struct ContextMenuOptions {
  608    pub min_entries_visible: usize,
  609    pub max_entries_visible: usize,
  610    pub placement: Option<ContextMenuPlacement>,
  611}
  612
  613#[derive(Debug, Clone, PartialEq, Eq)]
  614pub enum ContextMenuPlacement {
  615    Above,
  616    Below,
  617}
  618
  619#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  620struct EditorActionId(usize);
  621
  622impl EditorActionId {
  623    pub fn post_inc(&mut self) -> Self {
  624        let answer = self.0;
  625
  626        *self = Self(answer + 1);
  627
  628        Self(answer)
  629    }
  630}
  631
  632// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  633// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  634
  635type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Arc<[Range<Anchor>]>);
  636type GutterHighlight = (fn(&App) -> Hsla, Arc<[Range<Anchor>]>);
  637
  638#[derive(Default)]
  639struct ScrollbarMarkerState {
  640    scrollbar_size: Size<Pixels>,
  641    dirty: bool,
  642    markers: Arc<[PaintQuad]>,
  643    pending_refresh: Option<Task<Result<()>>>,
  644}
  645
  646impl ScrollbarMarkerState {
  647    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  648        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  649    }
  650}
  651
  652#[derive(Clone, Debug)]
  653struct RunnableTasks {
  654    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  655    offset: multi_buffer::Anchor,
  656    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  657    column: u32,
  658    // Values of all named captures, including those starting with '_'
  659    extra_variables: HashMap<String, String>,
  660    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  661    context_range: Range<BufferOffset>,
  662}
  663
  664impl RunnableTasks {
  665    fn resolve<'a>(
  666        &'a self,
  667        cx: &'a task::TaskContext,
  668    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  669        self.templates.iter().filter_map(|(kind, template)| {
  670            template
  671                .resolve_task(&kind.to_id_base(), cx)
  672                .map(|task| (kind.clone(), task))
  673        })
  674    }
  675}
  676
  677#[derive(Clone)]
  678struct ResolvedTasks {
  679    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  680    position: Anchor,
  681}
  682
  683#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  684struct BufferOffset(usize);
  685
  686// Addons allow storing per-editor state in other crates (e.g. Vim)
  687pub trait Addon: 'static {
  688    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  689
  690    fn render_buffer_header_controls(
  691        &self,
  692        _: &ExcerptInfo,
  693        _: &Window,
  694        _: &App,
  695    ) -> Option<AnyElement> {
  696        None
  697    }
  698
  699    fn to_any(&self) -> &dyn std::any::Any;
  700}
  701
  702/// A set of caret positions, registered when the editor was edited.
  703pub struct ChangeList {
  704    changes: Vec<Vec<Anchor>>,
  705    /// Currently "selected" change.
  706    position: Option<usize>,
  707}
  708
  709impl ChangeList {
  710    pub fn new() -> Self {
  711        Self {
  712            changes: Vec::new(),
  713            position: None,
  714        }
  715    }
  716
  717    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  718    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  719    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  720        if self.changes.is_empty() {
  721            return None;
  722        }
  723
  724        let prev = self.position.unwrap_or(self.changes.len());
  725        let next = if direction == Direction::Prev {
  726            prev.saturating_sub(count)
  727        } else {
  728            (prev + count).min(self.changes.len() - 1)
  729        };
  730        self.position = Some(next);
  731        self.changes.get(next).map(|anchors| anchors.as_slice())
  732    }
  733
  734    /// Adds a new change to the list, resetting the change list position.
  735    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  736        self.position.take();
  737        if pop_state {
  738            self.changes.pop();
  739        }
  740        self.changes.push(new_positions.clone());
  741    }
  742
  743    pub fn last(&self) -> Option<&[Anchor]> {
  744        self.changes.last().map(|anchors| anchors.as_slice())
  745    }
  746}
  747
  748/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  749///
  750/// See the [module level documentation](self) for more information.
  751pub struct Editor {
  752    focus_handle: FocusHandle,
  753    last_focused_descendant: Option<WeakFocusHandle>,
  754    /// The text buffer being edited
  755    buffer: Entity<MultiBuffer>,
  756    /// Map of how text in the buffer should be displayed.
  757    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  758    pub display_map: Entity<DisplayMap>,
  759    pub selections: SelectionsCollection,
  760    pub scroll_manager: ScrollManager,
  761    /// When inline assist editors are linked, they all render cursors because
  762    /// typing enters text into each of them, even the ones that aren't focused.
  763    pub(crate) show_cursor_when_unfocused: bool,
  764    columnar_selection_tail: Option<Anchor>,
  765    add_selections_state: Option<AddSelectionsState>,
  766    select_next_state: Option<SelectNextState>,
  767    select_prev_state: Option<SelectNextState>,
  768    selection_history: SelectionHistory,
  769    autoclose_regions: Vec<AutocloseRegion>,
  770    snippet_stack: InvalidationStack<SnippetState>,
  771    select_syntax_node_history: SelectSyntaxNodeHistory,
  772    ime_transaction: Option<TransactionId>,
  773    active_diagnostics: ActiveDiagnostic,
  774    show_inline_diagnostics: bool,
  775    inline_diagnostics_update: Task<()>,
  776    inline_diagnostics_enabled: bool,
  777    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  778    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  779    hard_wrap: Option<usize>,
  780
  781    // TODO: make this a access method
  782    pub project: Option<Entity<Project>>,
  783    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  784    completion_provider: Option<Box<dyn CompletionProvider>>,
  785    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  786    blink_manager: Entity<BlinkManager>,
  787    show_cursor_names: bool,
  788    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  789    pub show_local_selections: bool,
  790    mode: EditorMode,
  791    show_breadcrumbs: bool,
  792    show_gutter: bool,
  793    show_scrollbars: bool,
  794    disable_scrolling: bool,
  795    disable_expand_excerpt_buttons: bool,
  796    show_line_numbers: Option<bool>,
  797    use_relative_line_numbers: Option<bool>,
  798    show_git_diff_gutter: Option<bool>,
  799    show_code_actions: Option<bool>,
  800    show_runnables: Option<bool>,
  801    show_breakpoints: Option<bool>,
  802    show_wrap_guides: Option<bool>,
  803    show_indent_guides: Option<bool>,
  804    placeholder_text: Option<Arc<str>>,
  805    highlight_order: usize,
  806    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  807    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
  808    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
  809    scrollbar_marker_state: ScrollbarMarkerState,
  810    active_indent_guides_state: ActiveIndentGuidesState,
  811    nav_history: Option<ItemNavHistory>,
  812    context_menu: RefCell<Option<CodeContextMenu>>,
  813    context_menu_options: Option<ContextMenuOptions>,
  814    mouse_context_menu: Option<MouseContextMenu>,
  815    completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,
  816    signature_help_state: SignatureHelpState,
  817    auto_signature_help: Option<bool>,
  818    find_all_references_task_sources: Vec<Anchor>,
  819    next_completion_id: CompletionId,
  820    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
  821    code_actions_task: Option<Task<Result<()>>>,
  822    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  823    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  824    document_highlights_task: Option<Task<()>>,
  825    linked_editing_range_task: Option<Task<Option<()>>>,
  826    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
  827    pending_rename: Option<RenameState>,
  828    searchable: bool,
  829    cursor_shape: CursorShape,
  830    current_line_highlight: Option<CurrentLineHighlight>,
  831    collapse_matches: bool,
  832    autoindent_mode: Option<AutoindentMode>,
  833    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
  834    input_enabled: bool,
  835    use_modal_editing: bool,
  836    read_only: bool,
  837    leader_peer_id: Option<PeerId>,
  838    remote_id: Option<ViewId>,
  839    hover_state: HoverState,
  840    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
  841    gutter_hovered: bool,
  842    hovered_link_state: Option<HoveredLinkState>,
  843    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
  844    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
  845    active_inline_completion: Option<InlineCompletionState>,
  846    /// Used to prevent flickering as the user types while the menu is open
  847    stale_inline_completion_in_menu: Option<InlineCompletionState>,
  848    edit_prediction_settings: EditPredictionSettings,
  849    inline_completions_hidden_for_vim_mode: bool,
  850    show_inline_completions_override: Option<bool>,
  851    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
  852    edit_prediction_preview: EditPredictionPreview,
  853    edit_prediction_indent_conflict: bool,
  854    edit_prediction_requires_modifier_in_indent_conflict: bool,
  855    inlay_hint_cache: InlayHintCache,
  856    next_inlay_id: usize,
  857    _subscriptions: Vec<Subscription>,
  858    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
  859    gutter_dimensions: GutterDimensions,
  860    style: Option<EditorStyle>,
  861    text_style_refinement: Option<TextStyleRefinement>,
  862    next_editor_action_id: EditorActionId,
  863    editor_actions:
  864        Rc<RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&mut Window, &mut Context<Self>)>>>>,
  865    use_autoclose: bool,
  866    use_auto_surround: bool,
  867    auto_replace_emoji_shortcode: bool,
  868    jsx_tag_auto_close_enabled_in_any_buffer: bool,
  869    show_git_blame_gutter: bool,
  870    show_git_blame_inline: bool,
  871    show_git_blame_inline_delay_task: Option<Task<()>>,
  872    pub git_blame_inline_tooltip: Option<AnyWeakEntity>,
  873    git_blame_inline_enabled: bool,
  874    render_diff_hunk_controls: RenderDiffHunkControlsFn,
  875    serialize_dirty_buffers: bool,
  876    show_selection_menu: Option<bool>,
  877    blame: Option<Entity<GitBlame>>,
  878    blame_subscription: Option<Subscription>,
  879    custom_context_menu: Option<
  880        Box<
  881            dyn 'static
  882                + Fn(
  883                    &mut Self,
  884                    DisplayPoint,
  885                    &mut Window,
  886                    &mut Context<Self>,
  887                ) -> Option<Entity<ui::ContextMenu>>,
  888        >,
  889    >,
  890    last_bounds: Option<Bounds<Pixels>>,
  891    last_position_map: Option<Rc<PositionMap>>,
  892    expect_bounds_change: Option<Bounds<Pixels>>,
  893    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
  894    tasks_update_task: Option<Task<()>>,
  895    breakpoint_store: Option<Entity<BreakpointStore>>,
  896    /// Allow's a user to create a breakpoint by selecting this indicator
  897    /// It should be None while a user is not hovering over the gutter
  898    /// Otherwise it represents the point that the breakpoint will be shown
  899    gutter_breakpoint_indicator: (Option<(DisplayPoint, bool)>, Option<Task<()>>),
  900    in_project_search: bool,
  901    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
  902    breadcrumb_header: Option<String>,
  903    focused_block: Option<FocusedBlock>,
  904    next_scroll_position: NextScrollCursorCenterTopBottom,
  905    addons: HashMap<TypeId, Box<dyn Addon>>,
  906    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
  907    load_diff_task: Option<Shared<Task<()>>>,
  908    selection_mark_mode: bool,
  909    toggle_fold_multiple_buffers: Task<()>,
  910    _scroll_cursor_center_top_bottom_task: Task<()>,
  911    serialize_selections: Task<()>,
  912    serialize_folds: Task<()>,
  913    mouse_cursor_hidden: bool,
  914    hide_mouse_mode: HideMouseMode,
  915    pub change_list: ChangeList,
  916}
  917
  918#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
  919enum NextScrollCursorCenterTopBottom {
  920    #[default]
  921    Center,
  922    Top,
  923    Bottom,
  924}
  925
  926impl NextScrollCursorCenterTopBottom {
  927    fn next(&self) -> Self {
  928        match self {
  929            Self::Center => Self::Top,
  930            Self::Top => Self::Bottom,
  931            Self::Bottom => Self::Center,
  932        }
  933    }
  934}
  935
  936#[derive(Clone)]
  937pub struct EditorSnapshot {
  938    pub mode: EditorMode,
  939    show_gutter: bool,
  940    show_line_numbers: Option<bool>,
  941    show_git_diff_gutter: Option<bool>,
  942    show_code_actions: Option<bool>,
  943    show_runnables: Option<bool>,
  944    show_breakpoints: Option<bool>,
  945    git_blame_gutter_max_author_length: Option<usize>,
  946    pub display_snapshot: DisplaySnapshot,
  947    pub placeholder_text: Option<Arc<str>>,
  948    is_focused: bool,
  949    scroll_anchor: ScrollAnchor,
  950    ongoing_scroll: OngoingScroll,
  951    current_line_highlight: CurrentLineHighlight,
  952    gutter_hovered: bool,
  953}
  954
  955#[derive(Default, Debug, Clone, Copy)]
  956pub struct GutterDimensions {
  957    pub left_padding: Pixels,
  958    pub right_padding: Pixels,
  959    pub width: Pixels,
  960    pub margin: Pixels,
  961    pub git_blame_entries_width: Option<Pixels>,
  962}
  963
  964impl GutterDimensions {
  965    /// The full width of the space taken up by the gutter.
  966    pub fn full_width(&self) -> Pixels {
  967        self.margin + self.width
  968    }
  969
  970    /// The width of the space reserved for the fold indicators,
  971    /// use alongside 'justify_end' and `gutter_width` to
  972    /// right align content with the line numbers
  973    pub fn fold_area_width(&self) -> Pixels {
  974        self.margin + self.right_padding
  975    }
  976}
  977
  978#[derive(Debug)]
  979pub struct RemoteSelection {
  980    pub replica_id: ReplicaId,
  981    pub selection: Selection<Anchor>,
  982    pub cursor_shape: CursorShape,
  983    pub peer_id: PeerId,
  984    pub line_mode: bool,
  985    pub participant_index: Option<ParticipantIndex>,
  986    pub user_name: Option<SharedString>,
  987}
  988
  989#[derive(Clone, Debug)]
  990struct SelectionHistoryEntry {
  991    selections: Arc<[Selection<Anchor>]>,
  992    select_next_state: Option<SelectNextState>,
  993    select_prev_state: Option<SelectNextState>,
  994    add_selections_state: Option<AddSelectionsState>,
  995}
  996
  997enum SelectionHistoryMode {
  998    Normal,
  999    Undoing,
 1000    Redoing,
 1001}
 1002
 1003#[derive(Clone, PartialEq, Eq, Hash)]
 1004struct HoveredCursor {
 1005    replica_id: u16,
 1006    selection_id: usize,
 1007}
 1008
 1009impl Default for SelectionHistoryMode {
 1010    fn default() -> Self {
 1011        Self::Normal
 1012    }
 1013}
 1014
 1015#[derive(Default)]
 1016struct SelectionHistory {
 1017    #[allow(clippy::type_complexity)]
 1018    selections_by_transaction:
 1019        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1020    mode: SelectionHistoryMode,
 1021    undo_stack: VecDeque<SelectionHistoryEntry>,
 1022    redo_stack: VecDeque<SelectionHistoryEntry>,
 1023}
 1024
 1025impl SelectionHistory {
 1026    fn insert_transaction(
 1027        &mut self,
 1028        transaction_id: TransactionId,
 1029        selections: Arc<[Selection<Anchor>]>,
 1030    ) {
 1031        self.selections_by_transaction
 1032            .insert(transaction_id, (selections, None));
 1033    }
 1034
 1035    #[allow(clippy::type_complexity)]
 1036    fn transaction(
 1037        &self,
 1038        transaction_id: TransactionId,
 1039    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1040        self.selections_by_transaction.get(&transaction_id)
 1041    }
 1042
 1043    #[allow(clippy::type_complexity)]
 1044    fn transaction_mut(
 1045        &mut self,
 1046        transaction_id: TransactionId,
 1047    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1048        self.selections_by_transaction.get_mut(&transaction_id)
 1049    }
 1050
 1051    fn push(&mut self, entry: SelectionHistoryEntry) {
 1052        if !entry.selections.is_empty() {
 1053            match self.mode {
 1054                SelectionHistoryMode::Normal => {
 1055                    self.push_undo(entry);
 1056                    self.redo_stack.clear();
 1057                }
 1058                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1059                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1060            }
 1061        }
 1062    }
 1063
 1064    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1065        if self
 1066            .undo_stack
 1067            .back()
 1068            .map_or(true, |e| e.selections != entry.selections)
 1069        {
 1070            self.undo_stack.push_back(entry);
 1071            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1072                self.undo_stack.pop_front();
 1073            }
 1074        }
 1075    }
 1076
 1077    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1078        if self
 1079            .redo_stack
 1080            .back()
 1081            .map_or(true, |e| e.selections != entry.selections)
 1082        {
 1083            self.redo_stack.push_back(entry);
 1084            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1085                self.redo_stack.pop_front();
 1086            }
 1087        }
 1088    }
 1089}
 1090
 1091struct RowHighlight {
 1092    index: usize,
 1093    range: Range<Anchor>,
 1094    color: Hsla,
 1095    should_autoscroll: bool,
 1096}
 1097
 1098#[derive(Clone, Debug)]
 1099struct AddSelectionsState {
 1100    above: bool,
 1101    stack: Vec<usize>,
 1102}
 1103
 1104#[derive(Clone)]
 1105struct SelectNextState {
 1106    query: AhoCorasick,
 1107    wordwise: bool,
 1108    done: bool,
 1109}
 1110
 1111impl std::fmt::Debug for SelectNextState {
 1112    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1113        f.debug_struct(std::any::type_name::<Self>())
 1114            .field("wordwise", &self.wordwise)
 1115            .field("done", &self.done)
 1116            .finish()
 1117    }
 1118}
 1119
 1120#[derive(Debug)]
 1121struct AutocloseRegion {
 1122    selection_id: usize,
 1123    range: Range<Anchor>,
 1124    pair: BracketPair,
 1125}
 1126
 1127#[derive(Debug)]
 1128struct SnippetState {
 1129    ranges: Vec<Vec<Range<Anchor>>>,
 1130    active_index: usize,
 1131    choices: Vec<Option<Vec<String>>>,
 1132}
 1133
 1134#[doc(hidden)]
 1135pub struct RenameState {
 1136    pub range: Range<Anchor>,
 1137    pub old_name: Arc<str>,
 1138    pub editor: Entity<Editor>,
 1139    block_id: CustomBlockId,
 1140}
 1141
 1142struct InvalidationStack<T>(Vec<T>);
 1143
 1144struct RegisteredInlineCompletionProvider {
 1145    provider: Arc<dyn InlineCompletionProviderHandle>,
 1146    _subscription: Subscription,
 1147}
 1148
 1149#[derive(Debug, PartialEq, Eq)]
 1150pub struct ActiveDiagnosticGroup {
 1151    pub active_range: Range<Anchor>,
 1152    pub active_message: String,
 1153    pub group_id: usize,
 1154    pub blocks: HashSet<CustomBlockId>,
 1155}
 1156
 1157#[derive(Debug, PartialEq, Eq)]
 1158#[allow(clippy::large_enum_variant)]
 1159pub(crate) enum ActiveDiagnostic {
 1160    None,
 1161    All,
 1162    Group(ActiveDiagnosticGroup),
 1163}
 1164
 1165#[derive(Serialize, Deserialize, Clone, Debug)]
 1166pub struct ClipboardSelection {
 1167    /// The number of bytes in this selection.
 1168    pub len: usize,
 1169    /// Whether this was a full-line selection.
 1170    pub is_entire_line: bool,
 1171    /// The indentation of the first line when this content was originally copied.
 1172    pub first_line_indent: u32,
 1173}
 1174
 1175// selections, scroll behavior, was newest selection reversed
 1176type SelectSyntaxNodeHistoryState = (
 1177    Box<[Selection<usize>]>,
 1178    SelectSyntaxNodeScrollBehavior,
 1179    bool,
 1180);
 1181
 1182#[derive(Default)]
 1183struct SelectSyntaxNodeHistory {
 1184    stack: Vec<SelectSyntaxNodeHistoryState>,
 1185    // disable temporarily to allow changing selections without losing the stack
 1186    pub disable_clearing: bool,
 1187}
 1188
 1189impl SelectSyntaxNodeHistory {
 1190    pub fn try_clear(&mut self) {
 1191        if !self.disable_clearing {
 1192            self.stack.clear();
 1193        }
 1194    }
 1195
 1196    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1197        self.stack.push(selection);
 1198    }
 1199
 1200    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1201        self.stack.pop()
 1202    }
 1203}
 1204
 1205enum SelectSyntaxNodeScrollBehavior {
 1206    CursorTop,
 1207    FitSelection,
 1208    CursorBottom,
 1209}
 1210
 1211#[derive(Debug)]
 1212pub(crate) struct NavigationData {
 1213    cursor_anchor: Anchor,
 1214    cursor_position: Point,
 1215    scroll_anchor: ScrollAnchor,
 1216    scroll_top_row: u32,
 1217}
 1218
 1219#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1220pub enum GotoDefinitionKind {
 1221    Symbol,
 1222    Declaration,
 1223    Type,
 1224    Implementation,
 1225}
 1226
 1227#[derive(Debug, Clone)]
 1228enum InlayHintRefreshReason {
 1229    ModifiersChanged(bool),
 1230    Toggle(bool),
 1231    SettingsChange(InlayHintSettings),
 1232    NewLinesShown,
 1233    BufferEdited(HashSet<Arc<Language>>),
 1234    RefreshRequested,
 1235    ExcerptsRemoved(Vec<ExcerptId>),
 1236}
 1237
 1238impl InlayHintRefreshReason {
 1239    fn description(&self) -> &'static str {
 1240        match self {
 1241            Self::ModifiersChanged(_) => "modifiers changed",
 1242            Self::Toggle(_) => "toggle",
 1243            Self::SettingsChange(_) => "settings change",
 1244            Self::NewLinesShown => "new lines shown",
 1245            Self::BufferEdited(_) => "buffer edited",
 1246            Self::RefreshRequested => "refresh requested",
 1247            Self::ExcerptsRemoved(_) => "excerpts removed",
 1248        }
 1249    }
 1250}
 1251
 1252pub enum FormatTarget {
 1253    Buffers,
 1254    Ranges(Vec<Range<MultiBufferPoint>>),
 1255}
 1256
 1257pub(crate) struct FocusedBlock {
 1258    id: BlockId,
 1259    focus_handle: WeakFocusHandle,
 1260}
 1261
 1262#[derive(Clone)]
 1263enum JumpData {
 1264    MultiBufferRow {
 1265        row: MultiBufferRow,
 1266        line_offset_from_top: u32,
 1267    },
 1268    MultiBufferPoint {
 1269        excerpt_id: ExcerptId,
 1270        position: Point,
 1271        anchor: text::Anchor,
 1272        line_offset_from_top: u32,
 1273    },
 1274}
 1275
 1276pub enum MultibufferSelectionMode {
 1277    First,
 1278    All,
 1279}
 1280
 1281#[derive(Clone, Copy, Debug, Default)]
 1282pub struct RewrapOptions {
 1283    pub override_language_settings: bool,
 1284    pub preserve_existing_whitespace: bool,
 1285}
 1286
 1287impl Editor {
 1288    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1289        let buffer = cx.new(|cx| Buffer::local("", cx));
 1290        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1291        Self::new(
 1292            EditorMode::SingleLine { auto_width: false },
 1293            buffer,
 1294            None,
 1295            window,
 1296            cx,
 1297        )
 1298    }
 1299
 1300    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1301        let buffer = cx.new(|cx| Buffer::local("", cx));
 1302        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1303        Self::new(EditorMode::full(), buffer, None, window, cx)
 1304    }
 1305
 1306    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1307        let buffer = cx.new(|cx| Buffer::local("", cx));
 1308        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1309        Self::new(
 1310            EditorMode::SingleLine { auto_width: true },
 1311            buffer,
 1312            None,
 1313            window,
 1314            cx,
 1315        )
 1316    }
 1317
 1318    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1319        let buffer = cx.new(|cx| Buffer::local("", cx));
 1320        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1321        Self::new(
 1322            EditorMode::AutoHeight { max_lines },
 1323            buffer,
 1324            None,
 1325            window,
 1326            cx,
 1327        )
 1328    }
 1329
 1330    pub fn for_buffer(
 1331        buffer: Entity<Buffer>,
 1332        project: Option<Entity<Project>>,
 1333        window: &mut Window,
 1334        cx: &mut Context<Self>,
 1335    ) -> Self {
 1336        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1337        Self::new(EditorMode::full(), buffer, project, window, cx)
 1338    }
 1339
 1340    pub fn for_multibuffer(
 1341        buffer: Entity<MultiBuffer>,
 1342        project: Option<Entity<Project>>,
 1343        window: &mut Window,
 1344        cx: &mut Context<Self>,
 1345    ) -> Self {
 1346        Self::new(EditorMode::full(), buffer, project, window, cx)
 1347    }
 1348
 1349    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1350        let mut clone = Self::new(
 1351            self.mode,
 1352            self.buffer.clone(),
 1353            self.project.clone(),
 1354            window,
 1355            cx,
 1356        );
 1357        self.display_map.update(cx, |display_map, cx| {
 1358            let snapshot = display_map.snapshot(cx);
 1359            clone.display_map.update(cx, |display_map, cx| {
 1360                display_map.set_state(&snapshot, cx);
 1361            });
 1362        });
 1363        clone.folds_did_change(cx);
 1364        clone.selections.clone_state(&self.selections);
 1365        clone.scroll_manager.clone_state(&self.scroll_manager);
 1366        clone.searchable = self.searchable;
 1367        clone.read_only = self.read_only;
 1368        clone
 1369    }
 1370
 1371    pub fn new(
 1372        mode: EditorMode,
 1373        buffer: Entity<MultiBuffer>,
 1374        project: Option<Entity<Project>>,
 1375        window: &mut Window,
 1376        cx: &mut Context<Self>,
 1377    ) -> Self {
 1378        let style = window.text_style();
 1379        let font_size = style.font_size.to_pixels(window.rem_size());
 1380        let editor = cx.entity().downgrade();
 1381        let fold_placeholder = FoldPlaceholder {
 1382            constrain_width: true,
 1383            render: Arc::new(move |fold_id, fold_range, cx| {
 1384                let editor = editor.clone();
 1385                div()
 1386                    .id(fold_id)
 1387                    .bg(cx.theme().colors().ghost_element_background)
 1388                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1389                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1390                    .rounded_xs()
 1391                    .size_full()
 1392                    .cursor_pointer()
 1393                    .child("")
 1394                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1395                    .on_click(move |_, _window, cx| {
 1396                        editor
 1397                            .update(cx, |editor, cx| {
 1398                                editor.unfold_ranges(
 1399                                    &[fold_range.start..fold_range.end],
 1400                                    true,
 1401                                    false,
 1402                                    cx,
 1403                                );
 1404                                cx.stop_propagation();
 1405                            })
 1406                            .ok();
 1407                    })
 1408                    .into_any()
 1409            }),
 1410            merge_adjacent: true,
 1411            ..Default::default()
 1412        };
 1413        let display_map = cx.new(|cx| {
 1414            DisplayMap::new(
 1415                buffer.clone(),
 1416                style.font(),
 1417                font_size,
 1418                None,
 1419                FILE_HEADER_HEIGHT,
 1420                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1421                fold_placeholder,
 1422                cx,
 1423            )
 1424        });
 1425
 1426        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1427
 1428        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1429
 1430        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1431            .then(|| language_settings::SoftWrap::None);
 1432
 1433        let mut project_subscriptions = Vec::new();
 1434        if mode.is_full() {
 1435            if let Some(project) = project.as_ref() {
 1436                project_subscriptions.push(cx.subscribe_in(
 1437                    project,
 1438                    window,
 1439                    |editor, _, event, window, cx| match event {
 1440                        project::Event::RefreshCodeLens => {
 1441                            // we always query lens with actions, without storing them, always refreshing them
 1442                        }
 1443                        project::Event::RefreshInlayHints => {
 1444                            editor
 1445                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1446                        }
 1447                        project::Event::SnippetEdit(id, snippet_edits) => {
 1448                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1449                                let focus_handle = editor.focus_handle(cx);
 1450                                if focus_handle.is_focused(window) {
 1451                                    let snapshot = buffer.read(cx).snapshot();
 1452                                    for (range, snippet) in snippet_edits {
 1453                                        let editor_range =
 1454                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1455                                        editor
 1456                                            .insert_snippet(
 1457                                                &[editor_range],
 1458                                                snippet.clone(),
 1459                                                window,
 1460                                                cx,
 1461                                            )
 1462                                            .ok();
 1463                                    }
 1464                                }
 1465                            }
 1466                        }
 1467                        _ => {}
 1468                    },
 1469                ));
 1470                if let Some(task_inventory) = project
 1471                    .read(cx)
 1472                    .task_store()
 1473                    .read(cx)
 1474                    .task_inventory()
 1475                    .cloned()
 1476                {
 1477                    project_subscriptions.push(cx.observe_in(
 1478                        &task_inventory,
 1479                        window,
 1480                        |editor, _, window, cx| {
 1481                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1482                        },
 1483                    ));
 1484                };
 1485
 1486                project_subscriptions.push(cx.subscribe_in(
 1487                    &project.read(cx).breakpoint_store(),
 1488                    window,
 1489                    |editor, _, event, window, cx| match event {
 1490                        BreakpointStoreEvent::ActiveDebugLineChanged => {
 1491                            if editor.go_to_active_debug_line(window, cx) {
 1492                                cx.stop_propagation();
 1493                            }
 1494                        }
 1495                        _ => {}
 1496                    },
 1497                ));
 1498            }
 1499        }
 1500
 1501        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1502
 1503        let inlay_hint_settings =
 1504            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1505        let focus_handle = cx.focus_handle();
 1506        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1507            .detach();
 1508        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1509            .detach();
 1510        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1511            .detach();
 1512        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1513            .detach();
 1514
 1515        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1516            Some(false)
 1517        } else {
 1518            None
 1519        };
 1520
 1521        let breakpoint_store = match (mode, project.as_ref()) {
 1522            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1523            _ => None,
 1524        };
 1525
 1526        let mut code_action_providers = Vec::new();
 1527        let mut load_uncommitted_diff = None;
 1528        if let Some(project) = project.clone() {
 1529            load_uncommitted_diff = Some(
 1530                get_uncommitted_diff_for_buffer(
 1531                    &project,
 1532                    buffer.read(cx).all_buffers(),
 1533                    buffer.clone(),
 1534                    cx,
 1535                )
 1536                .shared(),
 1537            );
 1538            code_action_providers.push(Rc::new(project) as Rc<_>);
 1539        }
 1540
 1541        let mut this = Self {
 1542            focus_handle,
 1543            show_cursor_when_unfocused: false,
 1544            last_focused_descendant: None,
 1545            buffer: buffer.clone(),
 1546            display_map: display_map.clone(),
 1547            selections,
 1548            scroll_manager: ScrollManager::new(cx),
 1549            columnar_selection_tail: None,
 1550            add_selections_state: None,
 1551            select_next_state: None,
 1552            select_prev_state: None,
 1553            selection_history: Default::default(),
 1554            autoclose_regions: Default::default(),
 1555            snippet_stack: Default::default(),
 1556            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1557            ime_transaction: Default::default(),
 1558            active_diagnostics: ActiveDiagnostic::None,
 1559            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1560            inline_diagnostics_update: Task::ready(()),
 1561            inline_diagnostics: Vec::new(),
 1562            soft_wrap_mode_override,
 1563            hard_wrap: None,
 1564            completion_provider: project.clone().map(|project| Box::new(project) as _),
 1565            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1566            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1567            project,
 1568            blink_manager: blink_manager.clone(),
 1569            show_local_selections: true,
 1570            show_scrollbars: true,
 1571            disable_scrolling: false,
 1572            mode,
 1573            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1574            show_gutter: mode.is_full(),
 1575            show_line_numbers: None,
 1576            use_relative_line_numbers: None,
 1577            disable_expand_excerpt_buttons: false,
 1578            show_git_diff_gutter: None,
 1579            show_code_actions: None,
 1580            show_runnables: None,
 1581            show_breakpoints: None,
 1582            show_wrap_guides: None,
 1583            show_indent_guides,
 1584            placeholder_text: None,
 1585            highlight_order: 0,
 1586            highlighted_rows: HashMap::default(),
 1587            background_highlights: Default::default(),
 1588            gutter_highlights: TreeMap::default(),
 1589            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1590            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1591            nav_history: None,
 1592            context_menu: RefCell::new(None),
 1593            context_menu_options: None,
 1594            mouse_context_menu: None,
 1595            completion_tasks: Default::default(),
 1596            signature_help_state: SignatureHelpState::default(),
 1597            auto_signature_help: None,
 1598            find_all_references_task_sources: Vec::new(),
 1599            next_completion_id: 0,
 1600            next_inlay_id: 0,
 1601            code_action_providers,
 1602            available_code_actions: Default::default(),
 1603            code_actions_task: Default::default(),
 1604            quick_selection_highlight_task: Default::default(),
 1605            debounced_selection_highlight_task: Default::default(),
 1606            document_highlights_task: Default::default(),
 1607            linked_editing_range_task: Default::default(),
 1608            pending_rename: Default::default(),
 1609            searchable: true,
 1610            cursor_shape: EditorSettings::get_global(cx)
 1611                .cursor_shape
 1612                .unwrap_or_default(),
 1613            current_line_highlight: None,
 1614            autoindent_mode: Some(AutoindentMode::EachLine),
 1615            collapse_matches: false,
 1616            workspace: None,
 1617            input_enabled: true,
 1618            use_modal_editing: mode.is_full(),
 1619            read_only: false,
 1620            use_autoclose: true,
 1621            use_auto_surround: true,
 1622            auto_replace_emoji_shortcode: false,
 1623            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1624            leader_peer_id: None,
 1625            remote_id: None,
 1626            hover_state: Default::default(),
 1627            pending_mouse_down: None,
 1628            hovered_link_state: Default::default(),
 1629            edit_prediction_provider: None,
 1630            active_inline_completion: None,
 1631            stale_inline_completion_in_menu: None,
 1632            edit_prediction_preview: EditPredictionPreview::Inactive {
 1633                released_too_fast: false,
 1634            },
 1635            inline_diagnostics_enabled: mode.is_full(),
 1636            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1637
 1638            gutter_hovered: false,
 1639            pixel_position_of_newest_cursor: None,
 1640            last_bounds: None,
 1641            last_position_map: None,
 1642            expect_bounds_change: None,
 1643            gutter_dimensions: GutterDimensions::default(),
 1644            style: None,
 1645            show_cursor_names: false,
 1646            hovered_cursors: Default::default(),
 1647            next_editor_action_id: EditorActionId::default(),
 1648            editor_actions: Rc::default(),
 1649            inline_completions_hidden_for_vim_mode: false,
 1650            show_inline_completions_override: None,
 1651            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1652            edit_prediction_settings: EditPredictionSettings::Disabled,
 1653            edit_prediction_indent_conflict: false,
 1654            edit_prediction_requires_modifier_in_indent_conflict: true,
 1655            custom_context_menu: None,
 1656            show_git_blame_gutter: false,
 1657            show_git_blame_inline: false,
 1658            show_selection_menu: None,
 1659            show_git_blame_inline_delay_task: None,
 1660            git_blame_inline_tooltip: None,
 1661            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1662            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1663            serialize_dirty_buffers: ProjectSettings::get_global(cx)
 1664                .session
 1665                .restore_unsaved_buffers,
 1666            blame: None,
 1667            blame_subscription: None,
 1668            tasks: Default::default(),
 1669
 1670            breakpoint_store,
 1671            gutter_breakpoint_indicator: (None, None),
 1672            _subscriptions: vec![
 1673                cx.observe(&buffer, Self::on_buffer_changed),
 1674                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1675                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1676                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1677                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1678                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1679                cx.observe_window_activation(window, |editor, window, cx| {
 1680                    let active = window.is_window_active();
 1681                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1682                        if active {
 1683                            blink_manager.enable(cx);
 1684                        } else {
 1685                            blink_manager.disable(cx);
 1686                        }
 1687                    });
 1688                }),
 1689            ],
 1690            tasks_update_task: None,
 1691            linked_edit_ranges: Default::default(),
 1692            in_project_search: false,
 1693            previous_search_ranges: None,
 1694            breadcrumb_header: None,
 1695            focused_block: None,
 1696            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 1697            addons: HashMap::default(),
 1698            registered_buffers: HashMap::default(),
 1699            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 1700            selection_mark_mode: false,
 1701            toggle_fold_multiple_buffers: Task::ready(()),
 1702            serialize_selections: Task::ready(()),
 1703            serialize_folds: Task::ready(()),
 1704            text_style_refinement: None,
 1705            load_diff_task: load_uncommitted_diff,
 1706            mouse_cursor_hidden: false,
 1707            hide_mouse_mode: EditorSettings::get_global(cx)
 1708                .hide_mouse
 1709                .unwrap_or_default(),
 1710            change_list: ChangeList::new(),
 1711        };
 1712        if let Some(breakpoints) = this.breakpoint_store.as_ref() {
 1713            this._subscriptions
 1714                .push(cx.observe(breakpoints, |_, _, cx| {
 1715                    cx.notify();
 1716                }));
 1717        }
 1718        this.tasks_update_task = Some(this.refresh_runnables(window, cx));
 1719        this._subscriptions.extend(project_subscriptions);
 1720
 1721        this._subscriptions.push(cx.subscribe_in(
 1722            &cx.entity(),
 1723            window,
 1724            |editor, _, e: &EditorEvent, window, cx| match e {
 1725                EditorEvent::ScrollPositionChanged { local, .. } => {
 1726                    if *local {
 1727                        let new_anchor = editor.scroll_manager.anchor();
 1728                        let snapshot = editor.snapshot(window, cx);
 1729                        editor.update_restoration_data(cx, move |data| {
 1730                            data.scroll_position = (
 1731                                new_anchor.top_row(&snapshot.buffer_snapshot),
 1732                                new_anchor.offset,
 1733                            );
 1734                        });
 1735                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 1736                    }
 1737                }
 1738                EditorEvent::Edited { .. } => {
 1739                    if !vim_enabled(cx) {
 1740                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 1741                        let pop_state = editor
 1742                            .change_list
 1743                            .last()
 1744                            .map(|previous| {
 1745                                previous.len() == selections.len()
 1746                                    && previous.iter().enumerate().all(|(ix, p)| {
 1747                                        p.to_display_point(&map).row()
 1748                                            == selections[ix].head().row()
 1749                                    })
 1750                            })
 1751                            .unwrap_or(false);
 1752                        let new_positions = selections
 1753                            .into_iter()
 1754                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 1755                            .collect();
 1756                        editor
 1757                            .change_list
 1758                            .push_to_change_list(pop_state, new_positions);
 1759                    }
 1760                }
 1761                _ => (),
 1762            },
 1763        ));
 1764
 1765        this.end_selection(window, cx);
 1766        this.scroll_manager.show_scrollbars(window, cx);
 1767        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut this, &buffer, cx);
 1768
 1769        if mode.is_full() {
 1770            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 1771            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 1772
 1773            if this.git_blame_inline_enabled {
 1774                this.git_blame_inline_enabled = true;
 1775                this.start_git_blame_inline(false, window, cx);
 1776            }
 1777
 1778            this.go_to_active_debug_line(window, cx);
 1779
 1780            if let Some(buffer) = buffer.read(cx).as_singleton() {
 1781                if let Some(project) = this.project.as_ref() {
 1782                    let handle = project.update(cx, |project, cx| {
 1783                        project.register_buffer_with_language_servers(&buffer, cx)
 1784                    });
 1785                    this.registered_buffers
 1786                        .insert(buffer.read(cx).remote_id(), handle);
 1787                }
 1788            }
 1789        }
 1790
 1791        this.report_editor_event("Editor Opened", None, cx);
 1792        this
 1793    }
 1794
 1795    pub fn deploy_mouse_context_menu(
 1796        &mut self,
 1797        position: gpui::Point<Pixels>,
 1798        context_menu: Entity<ContextMenu>,
 1799        window: &mut Window,
 1800        cx: &mut Context<Self>,
 1801    ) {
 1802        self.mouse_context_menu = Some(MouseContextMenu::new(
 1803            self,
 1804            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 1805            context_menu,
 1806            window,
 1807            cx,
 1808        ));
 1809    }
 1810
 1811    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 1812        self.mouse_context_menu
 1813            .as_ref()
 1814            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 1815    }
 1816
 1817    fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 1818        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 1819    }
 1820
 1821    fn key_context_internal(
 1822        &self,
 1823        has_active_edit_prediction: bool,
 1824        window: &Window,
 1825        cx: &App,
 1826    ) -> KeyContext {
 1827        let mut key_context = KeyContext::new_with_defaults();
 1828        key_context.add("Editor");
 1829        let mode = match self.mode {
 1830            EditorMode::SingleLine { .. } => "single_line",
 1831            EditorMode::AutoHeight { .. } => "auto_height",
 1832            EditorMode::Full { .. } => "full",
 1833        };
 1834
 1835        if EditorSettings::jupyter_enabled(cx) {
 1836            key_context.add("jupyter");
 1837        }
 1838
 1839        key_context.set("mode", mode);
 1840        if self.pending_rename.is_some() {
 1841            key_context.add("renaming");
 1842        }
 1843
 1844        match self.context_menu.borrow().as_ref() {
 1845            Some(CodeContextMenu::Completions(_)) => {
 1846                key_context.add("menu");
 1847                key_context.add("showing_completions");
 1848            }
 1849            Some(CodeContextMenu::CodeActions(_)) => {
 1850                key_context.add("menu");
 1851                key_context.add("showing_code_actions")
 1852            }
 1853            None => {}
 1854        }
 1855
 1856        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 1857        if !self.focus_handle(cx).contains_focused(window, cx)
 1858            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 1859        {
 1860            for addon in self.addons.values() {
 1861                addon.extend_key_context(&mut key_context, cx)
 1862            }
 1863        }
 1864
 1865        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 1866            if let Some(extension) = singleton_buffer
 1867                .read(cx)
 1868                .file()
 1869                .and_then(|file| file.path().extension()?.to_str())
 1870            {
 1871                key_context.set("extension", extension.to_string());
 1872            }
 1873        } else {
 1874            key_context.add("multibuffer");
 1875        }
 1876
 1877        if has_active_edit_prediction {
 1878            if self.edit_prediction_in_conflict() {
 1879                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 1880            } else {
 1881                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 1882                key_context.add("copilot_suggestion");
 1883            }
 1884        }
 1885
 1886        if self.selection_mark_mode {
 1887            key_context.add("selection_mode");
 1888        }
 1889
 1890        key_context
 1891    }
 1892
 1893    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 1894        self.mouse_cursor_hidden = match origin {
 1895            HideMouseCursorOrigin::TypingAction => {
 1896                matches!(
 1897                    self.hide_mouse_mode,
 1898                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 1899                )
 1900            }
 1901            HideMouseCursorOrigin::MovementAction => {
 1902                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 1903            }
 1904        };
 1905    }
 1906
 1907    pub fn edit_prediction_in_conflict(&self) -> bool {
 1908        if !self.show_edit_predictions_in_menu() {
 1909            return false;
 1910        }
 1911
 1912        let showing_completions = self
 1913            .context_menu
 1914            .borrow()
 1915            .as_ref()
 1916            .map_or(false, |context| {
 1917                matches!(context, CodeContextMenu::Completions(_))
 1918            });
 1919
 1920        showing_completions
 1921            || self.edit_prediction_requires_modifier()
 1922            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 1923            // bindings to insert tab characters.
 1924            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 1925    }
 1926
 1927    pub fn accept_edit_prediction_keybind(
 1928        &self,
 1929        window: &Window,
 1930        cx: &App,
 1931    ) -> AcceptEditPredictionBinding {
 1932        let key_context = self.key_context_internal(true, window, cx);
 1933        let in_conflict = self.edit_prediction_in_conflict();
 1934
 1935        AcceptEditPredictionBinding(
 1936            window
 1937                .bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 1938                .into_iter()
 1939                .filter(|binding| {
 1940                    !in_conflict
 1941                        || binding
 1942                            .keystrokes()
 1943                            .first()
 1944                            .map_or(false, |keystroke| keystroke.modifiers.modified())
 1945                })
 1946                .rev()
 1947                .min_by_key(|binding| {
 1948                    binding
 1949                        .keystrokes()
 1950                        .first()
 1951                        .map_or(u8::MAX, |k| k.modifiers.number_of_modifiers())
 1952                }),
 1953        )
 1954    }
 1955
 1956    pub fn new_file(
 1957        workspace: &mut Workspace,
 1958        _: &workspace::NewFile,
 1959        window: &mut Window,
 1960        cx: &mut Context<Workspace>,
 1961    ) {
 1962        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 1963            "Failed to create buffer",
 1964            window,
 1965            cx,
 1966            |e, _, _| match e.error_code() {
 1967                ErrorCode::RemoteUpgradeRequired => Some(format!(
 1968                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 1969                e.error_tag("required").unwrap_or("the latest version")
 1970            )),
 1971                _ => None,
 1972            },
 1973        );
 1974    }
 1975
 1976    pub fn new_in_workspace(
 1977        workspace: &mut Workspace,
 1978        window: &mut Window,
 1979        cx: &mut Context<Workspace>,
 1980    ) -> Task<Result<Entity<Editor>>> {
 1981        let project = workspace.project().clone();
 1982        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 1983
 1984        cx.spawn_in(window, async move |workspace, cx| {
 1985            let buffer = create.await?;
 1986            workspace.update_in(cx, |workspace, window, cx| {
 1987                let editor =
 1988                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 1989                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 1990                editor
 1991            })
 1992        })
 1993    }
 1994
 1995    fn new_file_vertical(
 1996        workspace: &mut Workspace,
 1997        _: &workspace::NewFileSplitVertical,
 1998        window: &mut Window,
 1999        cx: &mut Context<Workspace>,
 2000    ) {
 2001        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2002    }
 2003
 2004    fn new_file_horizontal(
 2005        workspace: &mut Workspace,
 2006        _: &workspace::NewFileSplitHorizontal,
 2007        window: &mut Window,
 2008        cx: &mut Context<Workspace>,
 2009    ) {
 2010        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2011    }
 2012
 2013    fn new_file_in_direction(
 2014        workspace: &mut Workspace,
 2015        direction: SplitDirection,
 2016        window: &mut Window,
 2017        cx: &mut Context<Workspace>,
 2018    ) {
 2019        let project = workspace.project().clone();
 2020        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2021
 2022        cx.spawn_in(window, async move |workspace, cx| {
 2023            let buffer = create.await?;
 2024            workspace.update_in(cx, move |workspace, window, cx| {
 2025                workspace.split_item(
 2026                    direction,
 2027                    Box::new(
 2028                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2029                    ),
 2030                    window,
 2031                    cx,
 2032                )
 2033            })?;
 2034            anyhow::Ok(())
 2035        })
 2036        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2037            match e.error_code() {
 2038                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2039                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2040                e.error_tag("required").unwrap_or("the latest version")
 2041            )),
 2042                _ => None,
 2043            }
 2044        });
 2045    }
 2046
 2047    pub fn leader_peer_id(&self) -> Option<PeerId> {
 2048        self.leader_peer_id
 2049    }
 2050
 2051    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2052        &self.buffer
 2053    }
 2054
 2055    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2056        self.workspace.as_ref()?.0.upgrade()
 2057    }
 2058
 2059    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2060        self.buffer().read(cx).title(cx)
 2061    }
 2062
 2063    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2064        let git_blame_gutter_max_author_length = self
 2065            .render_git_blame_gutter(cx)
 2066            .then(|| {
 2067                if let Some(blame) = self.blame.as_ref() {
 2068                    let max_author_length =
 2069                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2070                    Some(max_author_length)
 2071                } else {
 2072                    None
 2073                }
 2074            })
 2075            .flatten();
 2076
 2077        EditorSnapshot {
 2078            mode: self.mode,
 2079            show_gutter: self.show_gutter,
 2080            show_line_numbers: self.show_line_numbers,
 2081            show_git_diff_gutter: self.show_git_diff_gutter,
 2082            show_code_actions: self.show_code_actions,
 2083            show_runnables: self.show_runnables,
 2084            show_breakpoints: self.show_breakpoints,
 2085            git_blame_gutter_max_author_length,
 2086            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2087            scroll_anchor: self.scroll_manager.anchor(),
 2088            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2089            placeholder_text: self.placeholder_text.clone(),
 2090            is_focused: self.focus_handle.is_focused(window),
 2091            current_line_highlight: self
 2092                .current_line_highlight
 2093                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2094            gutter_hovered: self.gutter_hovered,
 2095        }
 2096    }
 2097
 2098    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2099        self.buffer.read(cx).language_at(point, cx)
 2100    }
 2101
 2102    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2103        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2104    }
 2105
 2106    pub fn active_excerpt(
 2107        &self,
 2108        cx: &App,
 2109    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2110        self.buffer
 2111            .read(cx)
 2112            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2113    }
 2114
 2115    pub fn mode(&self) -> EditorMode {
 2116        self.mode
 2117    }
 2118
 2119    pub fn set_mode(&mut self, mode: EditorMode) {
 2120        self.mode = mode;
 2121    }
 2122
 2123    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2124        self.collaboration_hub.as_deref()
 2125    }
 2126
 2127    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2128        self.collaboration_hub = Some(hub);
 2129    }
 2130
 2131    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2132        self.in_project_search = in_project_search;
 2133    }
 2134
 2135    pub fn set_custom_context_menu(
 2136        &mut self,
 2137        f: impl 'static
 2138        + Fn(
 2139            &mut Self,
 2140            DisplayPoint,
 2141            &mut Window,
 2142            &mut Context<Self>,
 2143        ) -> Option<Entity<ui::ContextMenu>>,
 2144    ) {
 2145        self.custom_context_menu = Some(Box::new(f))
 2146    }
 2147
 2148    pub fn set_completion_provider(&mut self, provider: Option<Box<dyn CompletionProvider>>) {
 2149        self.completion_provider = provider;
 2150    }
 2151
 2152    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2153        self.semantics_provider.clone()
 2154    }
 2155
 2156    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2157        self.semantics_provider = provider;
 2158    }
 2159
 2160    pub fn set_edit_prediction_provider<T>(
 2161        &mut self,
 2162        provider: Option<Entity<T>>,
 2163        window: &mut Window,
 2164        cx: &mut Context<Self>,
 2165    ) where
 2166        T: EditPredictionProvider,
 2167    {
 2168        self.edit_prediction_provider =
 2169            provider.map(|provider| RegisteredInlineCompletionProvider {
 2170                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2171                    if this.focus_handle.is_focused(window) {
 2172                        this.update_visible_inline_completion(window, cx);
 2173                    }
 2174                }),
 2175                provider: Arc::new(provider),
 2176            });
 2177        self.update_edit_prediction_settings(cx);
 2178        self.refresh_inline_completion(false, false, window, cx);
 2179    }
 2180
 2181    pub fn placeholder_text(&self) -> Option<&str> {
 2182        self.placeholder_text.as_deref()
 2183    }
 2184
 2185    pub fn set_placeholder_text(
 2186        &mut self,
 2187        placeholder_text: impl Into<Arc<str>>,
 2188        cx: &mut Context<Self>,
 2189    ) {
 2190        let placeholder_text = Some(placeholder_text.into());
 2191        if self.placeholder_text != placeholder_text {
 2192            self.placeholder_text = placeholder_text;
 2193            cx.notify();
 2194        }
 2195    }
 2196
 2197    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2198        self.cursor_shape = cursor_shape;
 2199
 2200        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2201        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2202
 2203        cx.notify();
 2204    }
 2205
 2206    pub fn set_current_line_highlight(
 2207        &mut self,
 2208        current_line_highlight: Option<CurrentLineHighlight>,
 2209    ) {
 2210        self.current_line_highlight = current_line_highlight;
 2211    }
 2212
 2213    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2214        self.collapse_matches = collapse_matches;
 2215    }
 2216
 2217    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2218        let buffers = self.buffer.read(cx).all_buffers();
 2219        let Some(project) = self.project.as_ref() else {
 2220            return;
 2221        };
 2222        project.update(cx, |project, cx| {
 2223            for buffer in buffers {
 2224                self.registered_buffers
 2225                    .entry(buffer.read(cx).remote_id())
 2226                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2227            }
 2228        })
 2229    }
 2230
 2231    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2232        if self.collapse_matches {
 2233            return range.start..range.start;
 2234        }
 2235        range.clone()
 2236    }
 2237
 2238    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2239        if self.display_map.read(cx).clip_at_line_ends != clip {
 2240            self.display_map
 2241                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2242        }
 2243    }
 2244
 2245    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2246        self.input_enabled = input_enabled;
 2247    }
 2248
 2249    pub fn set_inline_completions_hidden_for_vim_mode(
 2250        &mut self,
 2251        hidden: bool,
 2252        window: &mut Window,
 2253        cx: &mut Context<Self>,
 2254    ) {
 2255        if hidden != self.inline_completions_hidden_for_vim_mode {
 2256            self.inline_completions_hidden_for_vim_mode = hidden;
 2257            if hidden {
 2258                self.update_visible_inline_completion(window, cx);
 2259            } else {
 2260                self.refresh_inline_completion(true, false, window, cx);
 2261            }
 2262        }
 2263    }
 2264
 2265    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2266        self.menu_inline_completions_policy = value;
 2267    }
 2268
 2269    pub fn set_autoindent(&mut self, autoindent: bool) {
 2270        if autoindent {
 2271            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2272        } else {
 2273            self.autoindent_mode = None;
 2274        }
 2275    }
 2276
 2277    pub fn read_only(&self, cx: &App) -> bool {
 2278        self.read_only || self.buffer.read(cx).read_only()
 2279    }
 2280
 2281    pub fn set_read_only(&mut self, read_only: bool) {
 2282        self.read_only = read_only;
 2283    }
 2284
 2285    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2286        self.use_autoclose = autoclose;
 2287    }
 2288
 2289    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2290        self.use_auto_surround = auto_surround;
 2291    }
 2292
 2293    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2294        self.auto_replace_emoji_shortcode = auto_replace;
 2295    }
 2296
 2297    pub fn toggle_edit_predictions(
 2298        &mut self,
 2299        _: &ToggleEditPrediction,
 2300        window: &mut Window,
 2301        cx: &mut Context<Self>,
 2302    ) {
 2303        if self.show_inline_completions_override.is_some() {
 2304            self.set_show_edit_predictions(None, window, cx);
 2305        } else {
 2306            let show_edit_predictions = !self.edit_predictions_enabled();
 2307            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2308        }
 2309    }
 2310
 2311    pub fn set_show_edit_predictions(
 2312        &mut self,
 2313        show_edit_predictions: Option<bool>,
 2314        window: &mut Window,
 2315        cx: &mut Context<Self>,
 2316    ) {
 2317        self.show_inline_completions_override = show_edit_predictions;
 2318        self.update_edit_prediction_settings(cx);
 2319
 2320        if let Some(false) = show_edit_predictions {
 2321            self.discard_inline_completion(false, cx);
 2322        } else {
 2323            self.refresh_inline_completion(false, true, window, cx);
 2324        }
 2325    }
 2326
 2327    fn inline_completions_disabled_in_scope(
 2328        &self,
 2329        buffer: &Entity<Buffer>,
 2330        buffer_position: language::Anchor,
 2331        cx: &App,
 2332    ) -> bool {
 2333        let snapshot = buffer.read(cx).snapshot();
 2334        let settings = snapshot.settings_at(buffer_position, cx);
 2335
 2336        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2337            return false;
 2338        };
 2339
 2340        scope.override_name().map_or(false, |scope_name| {
 2341            settings
 2342                .edit_predictions_disabled_in
 2343                .iter()
 2344                .any(|s| s == scope_name)
 2345        })
 2346    }
 2347
 2348    pub fn set_use_modal_editing(&mut self, to: bool) {
 2349        self.use_modal_editing = to;
 2350    }
 2351
 2352    pub fn use_modal_editing(&self) -> bool {
 2353        self.use_modal_editing
 2354    }
 2355
 2356    fn selections_did_change(
 2357        &mut self,
 2358        local: bool,
 2359        old_cursor_position: &Anchor,
 2360        show_completions: bool,
 2361        window: &mut Window,
 2362        cx: &mut Context<Self>,
 2363    ) {
 2364        window.invalidate_character_coordinates();
 2365
 2366        // Copy selections to primary selection buffer
 2367        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2368        if local {
 2369            let selections = self.selections.all::<usize>(cx);
 2370            let buffer_handle = self.buffer.read(cx).read(cx);
 2371
 2372            let mut text = String::new();
 2373            for (index, selection) in selections.iter().enumerate() {
 2374                let text_for_selection = buffer_handle
 2375                    .text_for_range(selection.start..selection.end)
 2376                    .collect::<String>();
 2377
 2378                text.push_str(&text_for_selection);
 2379                if index != selections.len() - 1 {
 2380                    text.push('\n');
 2381                }
 2382            }
 2383
 2384            if !text.is_empty() {
 2385                cx.write_to_primary(ClipboardItem::new_string(text));
 2386            }
 2387        }
 2388
 2389        if self.focus_handle.is_focused(window) && self.leader_peer_id.is_none() {
 2390            self.buffer.update(cx, |buffer, cx| {
 2391                buffer.set_active_selections(
 2392                    &self.selections.disjoint_anchors(),
 2393                    self.selections.line_mode,
 2394                    self.cursor_shape,
 2395                    cx,
 2396                )
 2397            });
 2398        }
 2399        let display_map = self
 2400            .display_map
 2401            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2402        let buffer = &display_map.buffer_snapshot;
 2403        self.add_selections_state = None;
 2404        self.select_next_state = None;
 2405        self.select_prev_state = None;
 2406        self.select_syntax_node_history.try_clear();
 2407        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2408        self.snippet_stack
 2409            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2410        self.take_rename(false, window, cx);
 2411
 2412        let new_cursor_position = self.selections.newest_anchor().head();
 2413
 2414        self.push_to_nav_history(
 2415            *old_cursor_position,
 2416            Some(new_cursor_position.to_point(buffer)),
 2417            false,
 2418            cx,
 2419        );
 2420
 2421        if local {
 2422            let new_cursor_position = self.selections.newest_anchor().head();
 2423            let mut context_menu = self.context_menu.borrow_mut();
 2424            let completion_menu = match context_menu.as_ref() {
 2425                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2426                _ => {
 2427                    *context_menu = None;
 2428                    None
 2429                }
 2430            };
 2431            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2432                if !self.registered_buffers.contains_key(&buffer_id) {
 2433                    if let Some(project) = self.project.as_ref() {
 2434                        project.update(cx, |project, cx| {
 2435                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2436                                return;
 2437                            };
 2438                            self.registered_buffers.insert(
 2439                                buffer_id,
 2440                                project.register_buffer_with_language_servers(&buffer, cx),
 2441                            );
 2442                        })
 2443                    }
 2444                }
 2445            }
 2446
 2447            if let Some(completion_menu) = completion_menu {
 2448                let cursor_position = new_cursor_position.to_offset(buffer);
 2449                let (word_range, kind) =
 2450                    buffer.surrounding_word(completion_menu.initial_position, true);
 2451                if kind == Some(CharKind::Word)
 2452                    && word_range.to_inclusive().contains(&cursor_position)
 2453                {
 2454                    let mut completion_menu = completion_menu.clone();
 2455                    drop(context_menu);
 2456
 2457                    let query = Self::completion_query(buffer, cursor_position);
 2458                    cx.spawn(async move |this, cx| {
 2459                        completion_menu
 2460                            .filter(query.as_deref(), cx.background_executor().clone())
 2461                            .await;
 2462
 2463                        this.update(cx, |this, cx| {
 2464                            let mut context_menu = this.context_menu.borrow_mut();
 2465                            let Some(CodeContextMenu::Completions(menu)) = context_menu.as_ref()
 2466                            else {
 2467                                return;
 2468                            };
 2469
 2470                            if menu.id > completion_menu.id {
 2471                                return;
 2472                            }
 2473
 2474                            *context_menu = Some(CodeContextMenu::Completions(completion_menu));
 2475                            drop(context_menu);
 2476                            cx.notify();
 2477                        })
 2478                    })
 2479                    .detach();
 2480
 2481                    if show_completions {
 2482                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2483                    }
 2484                } else {
 2485                    drop(context_menu);
 2486                    self.hide_context_menu(window, cx);
 2487                }
 2488            } else {
 2489                drop(context_menu);
 2490            }
 2491
 2492            hide_hover(self, cx);
 2493
 2494            if old_cursor_position.to_display_point(&display_map).row()
 2495                != new_cursor_position.to_display_point(&display_map).row()
 2496            {
 2497                self.available_code_actions.take();
 2498            }
 2499            self.refresh_code_actions(window, cx);
 2500            self.refresh_document_highlights(cx);
 2501            self.refresh_selected_text_highlights(window, cx);
 2502            refresh_matching_bracket_highlights(self, window, cx);
 2503            self.update_visible_inline_completion(window, cx);
 2504            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2505            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2506            if self.git_blame_inline_enabled {
 2507                self.start_inline_blame_timer(window, cx);
 2508            }
 2509        }
 2510
 2511        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2512        cx.emit(EditorEvent::SelectionsChanged { local });
 2513
 2514        let selections = &self.selections.disjoint;
 2515        if selections.len() == 1 {
 2516            cx.emit(SearchEvent::ActiveMatchChanged)
 2517        }
 2518        if local {
 2519            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2520                let inmemory_selections = selections
 2521                    .iter()
 2522                    .map(|s| {
 2523                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2524                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2525                    })
 2526                    .collect();
 2527                self.update_restoration_data(cx, |data| {
 2528                    data.selections = inmemory_selections;
 2529                });
 2530
 2531                if WorkspaceSettings::get(None, cx).restore_on_startup
 2532                    != RestoreOnStartupBehavior::None
 2533                {
 2534                    if let Some(workspace_id) =
 2535                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2536                    {
 2537                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2538                        let selections = selections.clone();
 2539                        let background_executor = cx.background_executor().clone();
 2540                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2541                        self.serialize_selections = cx.background_spawn(async move {
 2542                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2543                    let db_selections = selections
 2544                        .iter()
 2545                        .map(|selection| {
 2546                            (
 2547                                selection.start.to_offset(&snapshot),
 2548                                selection.end.to_offset(&snapshot),
 2549                            )
 2550                        })
 2551                        .collect();
 2552
 2553                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2554                        .await
 2555                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2556                        .log_err();
 2557                });
 2558                    }
 2559                }
 2560            }
 2561        }
 2562
 2563        cx.notify();
 2564    }
 2565
 2566    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2567        use text::ToOffset as _;
 2568        use text::ToPoint as _;
 2569
 2570        if WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None {
 2571            return;
 2572        }
 2573
 2574        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2575            return;
 2576        };
 2577
 2578        let snapshot = singleton.read(cx).snapshot();
 2579        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2580            let display_snapshot = display_map.snapshot(cx);
 2581
 2582            display_snapshot
 2583                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2584                .map(|fold| {
 2585                    fold.range.start.text_anchor.to_point(&snapshot)
 2586                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2587                })
 2588                .collect()
 2589        });
 2590        self.update_restoration_data(cx, |data| {
 2591            data.folds = inmemory_folds;
 2592        });
 2593
 2594        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2595            return;
 2596        };
 2597        let background_executor = cx.background_executor().clone();
 2598        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2599        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2600            display_map
 2601                .snapshot(cx)
 2602                .folds_in_range(0..snapshot.len())
 2603                .map(|fold| {
 2604                    (
 2605                        fold.range.start.text_anchor.to_offset(&snapshot),
 2606                        fold.range.end.text_anchor.to_offset(&snapshot),
 2607                    )
 2608                })
 2609                .collect()
 2610        });
 2611        self.serialize_folds = cx.background_spawn(async move {
 2612            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2613            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2614                .await
 2615                .with_context(|| {
 2616                    format!(
 2617                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2618                    )
 2619                })
 2620                .log_err();
 2621        });
 2622    }
 2623
 2624    pub fn sync_selections(
 2625        &mut self,
 2626        other: Entity<Editor>,
 2627        cx: &mut Context<Self>,
 2628    ) -> gpui::Subscription {
 2629        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2630        self.selections.change_with(cx, |selections| {
 2631            selections.select_anchors(other_selections);
 2632        });
 2633
 2634        let other_subscription =
 2635            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2636                EditorEvent::SelectionsChanged { local: true } => {
 2637                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2638                    if other_selections.is_empty() {
 2639                        return;
 2640                    }
 2641                    this.selections.change_with(cx, |selections| {
 2642                        selections.select_anchors(other_selections);
 2643                    });
 2644                }
 2645                _ => {}
 2646            });
 2647
 2648        let this_subscription =
 2649            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2650                EditorEvent::SelectionsChanged { local: true } => {
 2651                    let these_selections = this.selections.disjoint.to_vec();
 2652                    if these_selections.is_empty() {
 2653                        return;
 2654                    }
 2655                    other.update(cx, |other_editor, cx| {
 2656                        other_editor.selections.change_with(cx, |selections| {
 2657                            selections.select_anchors(these_selections);
 2658                        })
 2659                    });
 2660                }
 2661                _ => {}
 2662            });
 2663
 2664        Subscription::join(other_subscription, this_subscription)
 2665    }
 2666
 2667    pub fn change_selections<R>(
 2668        &mut self,
 2669        autoscroll: Option<Autoscroll>,
 2670        window: &mut Window,
 2671        cx: &mut Context<Self>,
 2672        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2673    ) -> R {
 2674        self.change_selections_inner(autoscroll, true, window, cx, change)
 2675    }
 2676
 2677    fn change_selections_inner<R>(
 2678        &mut self,
 2679        autoscroll: Option<Autoscroll>,
 2680        request_completions: bool,
 2681        window: &mut Window,
 2682        cx: &mut Context<Self>,
 2683        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2684    ) -> R {
 2685        let old_cursor_position = self.selections.newest_anchor().head();
 2686        self.push_to_selection_history();
 2687
 2688        let (changed, result) = self.selections.change_with(cx, change);
 2689
 2690        if changed {
 2691            if let Some(autoscroll) = autoscroll {
 2692                self.request_autoscroll(autoscroll, cx);
 2693            }
 2694            self.selections_did_change(true, &old_cursor_position, request_completions, window, cx);
 2695
 2696            if self.should_open_signature_help_automatically(
 2697                &old_cursor_position,
 2698                self.signature_help_state.backspace_pressed(),
 2699                cx,
 2700            ) {
 2701                self.show_signature_help(&ShowSignatureHelp, window, cx);
 2702            }
 2703            self.signature_help_state.set_backspace_pressed(false);
 2704        }
 2705
 2706        result
 2707    }
 2708
 2709    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2710    where
 2711        I: IntoIterator<Item = (Range<S>, T)>,
 2712        S: ToOffset,
 2713        T: Into<Arc<str>>,
 2714    {
 2715        if self.read_only(cx) {
 2716            return;
 2717        }
 2718
 2719        self.buffer
 2720            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 2721    }
 2722
 2723    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2724    where
 2725        I: IntoIterator<Item = (Range<S>, T)>,
 2726        S: ToOffset,
 2727        T: Into<Arc<str>>,
 2728    {
 2729        if self.read_only(cx) {
 2730            return;
 2731        }
 2732
 2733        self.buffer.update(cx, |buffer, cx| {
 2734            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 2735        });
 2736    }
 2737
 2738    pub fn edit_with_block_indent<I, S, T>(
 2739        &mut self,
 2740        edits: I,
 2741        original_indent_columns: Vec<Option<u32>>,
 2742        cx: &mut Context<Self>,
 2743    ) where
 2744        I: IntoIterator<Item = (Range<S>, T)>,
 2745        S: ToOffset,
 2746        T: Into<Arc<str>>,
 2747    {
 2748        if self.read_only(cx) {
 2749            return;
 2750        }
 2751
 2752        self.buffer.update(cx, |buffer, cx| {
 2753            buffer.edit(
 2754                edits,
 2755                Some(AutoindentMode::Block {
 2756                    original_indent_columns,
 2757                }),
 2758                cx,
 2759            )
 2760        });
 2761    }
 2762
 2763    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 2764        self.hide_context_menu(window, cx);
 2765
 2766        match phase {
 2767            SelectPhase::Begin {
 2768                position,
 2769                add,
 2770                click_count,
 2771            } => self.begin_selection(position, add, click_count, window, cx),
 2772            SelectPhase::BeginColumnar {
 2773                position,
 2774                goal_column,
 2775                reset,
 2776            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 2777            SelectPhase::Extend {
 2778                position,
 2779                click_count,
 2780            } => self.extend_selection(position, click_count, window, cx),
 2781            SelectPhase::Update {
 2782                position,
 2783                goal_column,
 2784                scroll_delta,
 2785            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 2786            SelectPhase::End => self.end_selection(window, cx),
 2787        }
 2788    }
 2789
 2790    fn extend_selection(
 2791        &mut self,
 2792        position: DisplayPoint,
 2793        click_count: usize,
 2794        window: &mut Window,
 2795        cx: &mut Context<Self>,
 2796    ) {
 2797        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2798        let tail = self.selections.newest::<usize>(cx).tail();
 2799        self.begin_selection(position, false, click_count, window, cx);
 2800
 2801        let position = position.to_offset(&display_map, Bias::Left);
 2802        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 2803
 2804        let mut pending_selection = self
 2805            .selections
 2806            .pending_anchor()
 2807            .expect("extend_selection not called with pending selection");
 2808        if position >= tail {
 2809            pending_selection.start = tail_anchor;
 2810        } else {
 2811            pending_selection.end = tail_anchor;
 2812            pending_selection.reversed = true;
 2813        }
 2814
 2815        let mut pending_mode = self.selections.pending_mode().unwrap();
 2816        match &mut pending_mode {
 2817            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 2818            _ => {}
 2819        }
 2820
 2821        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 2822            s.set_pending(pending_selection, pending_mode)
 2823        });
 2824    }
 2825
 2826    fn begin_selection(
 2827        &mut self,
 2828        position: DisplayPoint,
 2829        add: bool,
 2830        click_count: usize,
 2831        window: &mut Window,
 2832        cx: &mut Context<Self>,
 2833    ) {
 2834        if !self.focus_handle.is_focused(window) {
 2835            self.last_focused_descendant = None;
 2836            window.focus(&self.focus_handle);
 2837        }
 2838
 2839        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2840        let buffer = &display_map.buffer_snapshot;
 2841        let newest_selection = self.selections.newest_anchor().clone();
 2842        let position = display_map.clip_point(position, Bias::Left);
 2843
 2844        let start;
 2845        let end;
 2846        let mode;
 2847        let mut auto_scroll;
 2848        match click_count {
 2849            1 => {
 2850                start = buffer.anchor_before(position.to_point(&display_map));
 2851                end = start;
 2852                mode = SelectMode::Character;
 2853                auto_scroll = true;
 2854            }
 2855            2 => {
 2856                let range = movement::surrounding_word(&display_map, position);
 2857                start = buffer.anchor_before(range.start.to_point(&display_map));
 2858                end = buffer.anchor_before(range.end.to_point(&display_map));
 2859                mode = SelectMode::Word(start..end);
 2860                auto_scroll = true;
 2861            }
 2862            3 => {
 2863                let position = display_map
 2864                    .clip_point(position, Bias::Left)
 2865                    .to_point(&display_map);
 2866                let line_start = display_map.prev_line_boundary(position).0;
 2867                let next_line_start = buffer.clip_point(
 2868                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 2869                    Bias::Left,
 2870                );
 2871                start = buffer.anchor_before(line_start);
 2872                end = buffer.anchor_before(next_line_start);
 2873                mode = SelectMode::Line(start..end);
 2874                auto_scroll = true;
 2875            }
 2876            _ => {
 2877                start = buffer.anchor_before(0);
 2878                end = buffer.anchor_before(buffer.len());
 2879                mode = SelectMode::All;
 2880                auto_scroll = false;
 2881            }
 2882        }
 2883        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 2884
 2885        let point_to_delete: Option<usize> = {
 2886            let selected_points: Vec<Selection<Point>> =
 2887                self.selections.disjoint_in_range(start..end, cx);
 2888
 2889            if !add || click_count > 1 {
 2890                None
 2891            } else if !selected_points.is_empty() {
 2892                Some(selected_points[0].id)
 2893            } else {
 2894                let clicked_point_already_selected =
 2895                    self.selections.disjoint.iter().find(|selection| {
 2896                        selection.start.to_point(buffer) == start.to_point(buffer)
 2897                            || selection.end.to_point(buffer) == end.to_point(buffer)
 2898                    });
 2899
 2900                clicked_point_already_selected.map(|selection| selection.id)
 2901            }
 2902        };
 2903
 2904        let selections_count = self.selections.count();
 2905
 2906        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 2907            if let Some(point_to_delete) = point_to_delete {
 2908                s.delete(point_to_delete);
 2909
 2910                if selections_count == 1 {
 2911                    s.set_pending_anchor_range(start..end, mode);
 2912                }
 2913            } else {
 2914                if !add {
 2915                    s.clear_disjoint();
 2916                } else if click_count > 1 {
 2917                    s.delete(newest_selection.id)
 2918                }
 2919
 2920                s.set_pending_anchor_range(start..end, mode);
 2921            }
 2922        });
 2923    }
 2924
 2925    fn begin_columnar_selection(
 2926        &mut self,
 2927        position: DisplayPoint,
 2928        goal_column: u32,
 2929        reset: bool,
 2930        window: &mut Window,
 2931        cx: &mut Context<Self>,
 2932    ) {
 2933        if !self.focus_handle.is_focused(window) {
 2934            self.last_focused_descendant = None;
 2935            window.focus(&self.focus_handle);
 2936        }
 2937
 2938        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2939
 2940        if reset {
 2941            let pointer_position = display_map
 2942                .buffer_snapshot
 2943                .anchor_before(position.to_point(&display_map));
 2944
 2945            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 2946                s.clear_disjoint();
 2947                s.set_pending_anchor_range(
 2948                    pointer_position..pointer_position,
 2949                    SelectMode::Character,
 2950                );
 2951            });
 2952        }
 2953
 2954        let tail = self.selections.newest::<Point>(cx).tail();
 2955        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 2956
 2957        if !reset {
 2958            self.select_columns(
 2959                tail.to_display_point(&display_map),
 2960                position,
 2961                goal_column,
 2962                &display_map,
 2963                window,
 2964                cx,
 2965            );
 2966        }
 2967    }
 2968
 2969    fn update_selection(
 2970        &mut self,
 2971        position: DisplayPoint,
 2972        goal_column: u32,
 2973        scroll_delta: gpui::Point<f32>,
 2974        window: &mut Window,
 2975        cx: &mut Context<Self>,
 2976    ) {
 2977        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2978
 2979        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 2980            let tail = tail.to_display_point(&display_map);
 2981            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 2982        } else if let Some(mut pending) = self.selections.pending_anchor() {
 2983            let buffer = self.buffer.read(cx).snapshot(cx);
 2984            let head;
 2985            let tail;
 2986            let mode = self.selections.pending_mode().unwrap();
 2987            match &mode {
 2988                SelectMode::Character => {
 2989                    head = position.to_point(&display_map);
 2990                    tail = pending.tail().to_point(&buffer);
 2991                }
 2992                SelectMode::Word(original_range) => {
 2993                    let original_display_range = original_range.start.to_display_point(&display_map)
 2994                        ..original_range.end.to_display_point(&display_map);
 2995                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 2996                        ..original_display_range.end.to_point(&display_map);
 2997                    if movement::is_inside_word(&display_map, position)
 2998                        || original_display_range.contains(&position)
 2999                    {
 3000                        let word_range = movement::surrounding_word(&display_map, position);
 3001                        if word_range.start < original_display_range.start {
 3002                            head = word_range.start.to_point(&display_map);
 3003                        } else {
 3004                            head = word_range.end.to_point(&display_map);
 3005                        }
 3006                    } else {
 3007                        head = position.to_point(&display_map);
 3008                    }
 3009
 3010                    if head <= original_buffer_range.start {
 3011                        tail = original_buffer_range.end;
 3012                    } else {
 3013                        tail = original_buffer_range.start;
 3014                    }
 3015                }
 3016                SelectMode::Line(original_range) => {
 3017                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3018
 3019                    let position = display_map
 3020                        .clip_point(position, Bias::Left)
 3021                        .to_point(&display_map);
 3022                    let line_start = display_map.prev_line_boundary(position).0;
 3023                    let next_line_start = buffer.clip_point(
 3024                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3025                        Bias::Left,
 3026                    );
 3027
 3028                    if line_start < original_range.start {
 3029                        head = line_start
 3030                    } else {
 3031                        head = next_line_start
 3032                    }
 3033
 3034                    if head <= original_range.start {
 3035                        tail = original_range.end;
 3036                    } else {
 3037                        tail = original_range.start;
 3038                    }
 3039                }
 3040                SelectMode::All => {
 3041                    return;
 3042                }
 3043            };
 3044
 3045            if head < tail {
 3046                pending.start = buffer.anchor_before(head);
 3047                pending.end = buffer.anchor_before(tail);
 3048                pending.reversed = true;
 3049            } else {
 3050                pending.start = buffer.anchor_before(tail);
 3051                pending.end = buffer.anchor_before(head);
 3052                pending.reversed = false;
 3053            }
 3054
 3055            self.change_selections(None, window, cx, |s| {
 3056                s.set_pending(pending, mode);
 3057            });
 3058        } else {
 3059            log::error!("update_selection dispatched with no pending selection");
 3060            return;
 3061        }
 3062
 3063        self.apply_scroll_delta(scroll_delta, window, cx);
 3064        cx.notify();
 3065    }
 3066
 3067    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3068        self.columnar_selection_tail.take();
 3069        if self.selections.pending_anchor().is_some() {
 3070            let selections = self.selections.all::<usize>(cx);
 3071            self.change_selections(None, window, cx, |s| {
 3072                s.select(selections);
 3073                s.clear_pending();
 3074            });
 3075        }
 3076    }
 3077
 3078    fn select_columns(
 3079        &mut self,
 3080        tail: DisplayPoint,
 3081        head: DisplayPoint,
 3082        goal_column: u32,
 3083        display_map: &DisplaySnapshot,
 3084        window: &mut Window,
 3085        cx: &mut Context<Self>,
 3086    ) {
 3087        let start_row = cmp::min(tail.row(), head.row());
 3088        let end_row = cmp::max(tail.row(), head.row());
 3089        let start_column = cmp::min(tail.column(), goal_column);
 3090        let end_column = cmp::max(tail.column(), goal_column);
 3091        let reversed = start_column < tail.column();
 3092
 3093        let selection_ranges = (start_row.0..=end_row.0)
 3094            .map(DisplayRow)
 3095            .filter_map(|row| {
 3096                if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
 3097                    let start = display_map
 3098                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3099                        .to_point(display_map);
 3100                    let end = display_map
 3101                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3102                        .to_point(display_map);
 3103                    if reversed {
 3104                        Some(end..start)
 3105                    } else {
 3106                        Some(start..end)
 3107                    }
 3108                } else {
 3109                    None
 3110                }
 3111            })
 3112            .collect::<Vec<_>>();
 3113
 3114        self.change_selections(None, window, cx, |s| {
 3115            s.select_ranges(selection_ranges);
 3116        });
 3117        cx.notify();
 3118    }
 3119
 3120    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3121        self.selections
 3122            .all_adjusted(cx)
 3123            .iter()
 3124            .any(|selection| !selection.is_empty())
 3125    }
 3126
 3127    pub fn has_pending_nonempty_selection(&self) -> bool {
 3128        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3129            Some(Selection { start, end, .. }) => start != end,
 3130            None => false,
 3131        };
 3132
 3133        pending_nonempty_selection
 3134            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3135    }
 3136
 3137    pub fn has_pending_selection(&self) -> bool {
 3138        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3139    }
 3140
 3141    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3142        self.selection_mark_mode = false;
 3143
 3144        if self.clear_expanded_diff_hunks(cx) {
 3145            cx.notify();
 3146            return;
 3147        }
 3148        if self.dismiss_menus_and_popups(true, window, cx) {
 3149            return;
 3150        }
 3151
 3152        if self.mode.is_full()
 3153            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3154        {
 3155            return;
 3156        }
 3157
 3158        cx.propagate();
 3159    }
 3160
 3161    pub fn dismiss_menus_and_popups(
 3162        &mut self,
 3163        is_user_requested: bool,
 3164        window: &mut Window,
 3165        cx: &mut Context<Self>,
 3166    ) -> bool {
 3167        if self.take_rename(false, window, cx).is_some() {
 3168            return true;
 3169        }
 3170
 3171        if hide_hover(self, cx) {
 3172            return true;
 3173        }
 3174
 3175        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3176            return true;
 3177        }
 3178
 3179        if self.hide_context_menu(window, cx).is_some() {
 3180            return true;
 3181        }
 3182
 3183        if self.mouse_context_menu.take().is_some() {
 3184            return true;
 3185        }
 3186
 3187        if is_user_requested && self.discard_inline_completion(true, cx) {
 3188            return true;
 3189        }
 3190
 3191        if self.snippet_stack.pop().is_some() {
 3192            return true;
 3193        }
 3194
 3195        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3196            self.dismiss_diagnostics(cx);
 3197            return true;
 3198        }
 3199
 3200        false
 3201    }
 3202
 3203    fn linked_editing_ranges_for(
 3204        &self,
 3205        selection: Range<text::Anchor>,
 3206        cx: &App,
 3207    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3208        if self.linked_edit_ranges.is_empty() {
 3209            return None;
 3210        }
 3211        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3212            selection.end.buffer_id.and_then(|end_buffer_id| {
 3213                if selection.start.buffer_id != Some(end_buffer_id) {
 3214                    return None;
 3215                }
 3216                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3217                let snapshot = buffer.read(cx).snapshot();
 3218                self.linked_edit_ranges
 3219                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3220                    .map(|ranges| (ranges, snapshot, buffer))
 3221            })?;
 3222        use text::ToOffset as TO;
 3223        // find offset from the start of current range to current cursor position
 3224        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3225
 3226        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3227        let start_difference = start_offset - start_byte_offset;
 3228        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3229        let end_difference = end_offset - start_byte_offset;
 3230        // Current range has associated linked ranges.
 3231        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3232        for range in linked_ranges.iter() {
 3233            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3234            let end_offset = start_offset + end_difference;
 3235            let start_offset = start_offset + start_difference;
 3236            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3237                continue;
 3238            }
 3239            if self.selections.disjoint_anchor_ranges().any(|s| {
 3240                if s.start.buffer_id != selection.start.buffer_id
 3241                    || s.end.buffer_id != selection.end.buffer_id
 3242                {
 3243                    return false;
 3244                }
 3245                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3246                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3247            }) {
 3248                continue;
 3249            }
 3250            let start = buffer_snapshot.anchor_after(start_offset);
 3251            let end = buffer_snapshot.anchor_after(end_offset);
 3252            linked_edits
 3253                .entry(buffer.clone())
 3254                .or_default()
 3255                .push(start..end);
 3256        }
 3257        Some(linked_edits)
 3258    }
 3259
 3260    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3261        let text: Arc<str> = text.into();
 3262
 3263        if self.read_only(cx) {
 3264            return;
 3265        }
 3266
 3267        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3268
 3269        let selections = self.selections.all_adjusted(cx);
 3270        let mut bracket_inserted = false;
 3271        let mut edits = Vec::new();
 3272        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3273        let mut new_selections = Vec::with_capacity(selections.len());
 3274        let mut new_autoclose_regions = Vec::new();
 3275        let snapshot = self.buffer.read(cx).read(cx);
 3276        let mut clear_linked_edit_ranges = false;
 3277
 3278        for (selection, autoclose_region) in
 3279            self.selections_with_autoclose_regions(selections, &snapshot)
 3280        {
 3281            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3282                // Determine if the inserted text matches the opening or closing
 3283                // bracket of any of this language's bracket pairs.
 3284                let mut bracket_pair = None;
 3285                let mut is_bracket_pair_start = false;
 3286                let mut is_bracket_pair_end = false;
 3287                if !text.is_empty() {
 3288                    let mut bracket_pair_matching_end = None;
 3289                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3290                    //  and they are removing the character that triggered IME popup.
 3291                    for (pair, enabled) in scope.brackets() {
 3292                        if !pair.close && !pair.surround {
 3293                            continue;
 3294                        }
 3295
 3296                        if enabled && pair.start.ends_with(text.as_ref()) {
 3297                            let prefix_len = pair.start.len() - text.len();
 3298                            let preceding_text_matches_prefix = prefix_len == 0
 3299                                || (selection.start.column >= (prefix_len as u32)
 3300                                    && snapshot.contains_str_at(
 3301                                        Point::new(
 3302                                            selection.start.row,
 3303                                            selection.start.column - (prefix_len as u32),
 3304                                        ),
 3305                                        &pair.start[..prefix_len],
 3306                                    ));
 3307                            if preceding_text_matches_prefix {
 3308                                bracket_pair = Some(pair.clone());
 3309                                is_bracket_pair_start = true;
 3310                                break;
 3311                            }
 3312                        }
 3313                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3314                        {
 3315                            // take first bracket pair matching end, but don't break in case a later bracket
 3316                            // pair matches start
 3317                            bracket_pair_matching_end = Some(pair.clone());
 3318                        }
 3319                    }
 3320                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3321                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3322                        is_bracket_pair_end = true;
 3323                    }
 3324                }
 3325
 3326                if let Some(bracket_pair) = bracket_pair {
 3327                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3328                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3329                    let auto_surround =
 3330                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3331                    if selection.is_empty() {
 3332                        if is_bracket_pair_start {
 3333                            // If the inserted text is a suffix of an opening bracket and the
 3334                            // selection is preceded by the rest of the opening bracket, then
 3335                            // insert the closing bracket.
 3336                            let following_text_allows_autoclose = snapshot
 3337                                .chars_at(selection.start)
 3338                                .next()
 3339                                .map_or(true, |c| scope.should_autoclose_before(c));
 3340
 3341                            let preceding_text_allows_autoclose = selection.start.column == 0
 3342                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3343                                    true,
 3344                                    |c| {
 3345                                        bracket_pair.start != bracket_pair.end
 3346                                            || !snapshot
 3347                                                .char_classifier_at(selection.start)
 3348                                                .is_word(c)
 3349                                    },
 3350                                );
 3351
 3352                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3353                                && bracket_pair.start.len() == 1
 3354                            {
 3355                                let target = bracket_pair.start.chars().next().unwrap();
 3356                                let current_line_count = snapshot
 3357                                    .reversed_chars_at(selection.start)
 3358                                    .take_while(|&c| c != '\n')
 3359                                    .filter(|&c| c == target)
 3360                                    .count();
 3361                                current_line_count % 2 == 1
 3362                            } else {
 3363                                false
 3364                            };
 3365
 3366                            if autoclose
 3367                                && bracket_pair.close
 3368                                && following_text_allows_autoclose
 3369                                && preceding_text_allows_autoclose
 3370                                && !is_closing_quote
 3371                            {
 3372                                let anchor = snapshot.anchor_before(selection.end);
 3373                                new_selections.push((selection.map(|_| anchor), text.len()));
 3374                                new_autoclose_regions.push((
 3375                                    anchor,
 3376                                    text.len(),
 3377                                    selection.id,
 3378                                    bracket_pair.clone(),
 3379                                ));
 3380                                edits.push((
 3381                                    selection.range(),
 3382                                    format!("{}{}", text, bracket_pair.end).into(),
 3383                                ));
 3384                                bracket_inserted = true;
 3385                                continue;
 3386                            }
 3387                        }
 3388
 3389                        if let Some(region) = autoclose_region {
 3390                            // If the selection is followed by an auto-inserted closing bracket,
 3391                            // then don't insert that closing bracket again; just move the selection
 3392                            // past the closing bracket.
 3393                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3394                                && text.as_ref() == region.pair.end.as_str();
 3395                            if should_skip {
 3396                                let anchor = snapshot.anchor_after(selection.end);
 3397                                new_selections
 3398                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3399                                continue;
 3400                            }
 3401                        }
 3402
 3403                        let always_treat_brackets_as_autoclosed = snapshot
 3404                            .language_settings_at(selection.start, cx)
 3405                            .always_treat_brackets_as_autoclosed;
 3406                        if always_treat_brackets_as_autoclosed
 3407                            && is_bracket_pair_end
 3408                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3409                        {
 3410                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3411                            // and the inserted text is a closing bracket and the selection is followed
 3412                            // by the closing bracket then move the selection past the closing bracket.
 3413                            let anchor = snapshot.anchor_after(selection.end);
 3414                            new_selections.push((selection.map(|_| anchor), text.len()));
 3415                            continue;
 3416                        }
 3417                    }
 3418                    // If an opening bracket is 1 character long and is typed while
 3419                    // text is selected, then surround that text with the bracket pair.
 3420                    else if auto_surround
 3421                        && bracket_pair.surround
 3422                        && is_bracket_pair_start
 3423                        && bracket_pair.start.chars().count() == 1
 3424                    {
 3425                        edits.push((selection.start..selection.start, text.clone()));
 3426                        edits.push((
 3427                            selection.end..selection.end,
 3428                            bracket_pair.end.as_str().into(),
 3429                        ));
 3430                        bracket_inserted = true;
 3431                        new_selections.push((
 3432                            Selection {
 3433                                id: selection.id,
 3434                                start: snapshot.anchor_after(selection.start),
 3435                                end: snapshot.anchor_before(selection.end),
 3436                                reversed: selection.reversed,
 3437                                goal: selection.goal,
 3438                            },
 3439                            0,
 3440                        ));
 3441                        continue;
 3442                    }
 3443                }
 3444            }
 3445
 3446            if self.auto_replace_emoji_shortcode
 3447                && selection.is_empty()
 3448                && text.as_ref().ends_with(':')
 3449            {
 3450                if let Some(possible_emoji_short_code) =
 3451                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3452                {
 3453                    if !possible_emoji_short_code.is_empty() {
 3454                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3455                            let emoji_shortcode_start = Point::new(
 3456                                selection.start.row,
 3457                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3458                            );
 3459
 3460                            // Remove shortcode from buffer
 3461                            edits.push((
 3462                                emoji_shortcode_start..selection.start,
 3463                                "".to_string().into(),
 3464                            ));
 3465                            new_selections.push((
 3466                                Selection {
 3467                                    id: selection.id,
 3468                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3469                                    end: snapshot.anchor_before(selection.start),
 3470                                    reversed: selection.reversed,
 3471                                    goal: selection.goal,
 3472                                },
 3473                                0,
 3474                            ));
 3475
 3476                            // Insert emoji
 3477                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3478                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3479                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3480
 3481                            continue;
 3482                        }
 3483                    }
 3484                }
 3485            }
 3486
 3487            // If not handling any auto-close operation, then just replace the selected
 3488            // text with the given input and move the selection to the end of the
 3489            // newly inserted text.
 3490            let anchor = snapshot.anchor_after(selection.end);
 3491            if !self.linked_edit_ranges.is_empty() {
 3492                let start_anchor = snapshot.anchor_before(selection.start);
 3493
 3494                let is_word_char = text.chars().next().map_or(true, |char| {
 3495                    let classifier = snapshot.char_classifier_at(start_anchor.to_offset(&snapshot));
 3496                    classifier.is_word(char)
 3497                });
 3498
 3499                if is_word_char {
 3500                    if let Some(ranges) = self
 3501                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3502                    {
 3503                        for (buffer, edits) in ranges {
 3504                            linked_edits
 3505                                .entry(buffer.clone())
 3506                                .or_default()
 3507                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3508                        }
 3509                    }
 3510                } else {
 3511                    clear_linked_edit_ranges = true;
 3512                }
 3513            }
 3514
 3515            new_selections.push((selection.map(|_| anchor), 0));
 3516            edits.push((selection.start..selection.end, text.clone()));
 3517        }
 3518
 3519        drop(snapshot);
 3520
 3521        self.transact(window, cx, |this, window, cx| {
 3522            if clear_linked_edit_ranges {
 3523                this.linked_edit_ranges.clear();
 3524            }
 3525            let initial_buffer_versions =
 3526                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3527
 3528            this.buffer.update(cx, |buffer, cx| {
 3529                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3530            });
 3531            for (buffer, edits) in linked_edits {
 3532                buffer.update(cx, |buffer, cx| {
 3533                    let snapshot = buffer.snapshot();
 3534                    let edits = edits
 3535                        .into_iter()
 3536                        .map(|(range, text)| {
 3537                            use text::ToPoint as TP;
 3538                            let end_point = TP::to_point(&range.end, &snapshot);
 3539                            let start_point = TP::to_point(&range.start, &snapshot);
 3540                            (start_point..end_point, text)
 3541                        })
 3542                        .sorted_by_key(|(range, _)| range.start);
 3543                    buffer.edit(edits, None, cx);
 3544                })
 3545            }
 3546            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3547            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3548            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3549            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3550                .zip(new_selection_deltas)
 3551                .map(|(selection, delta)| Selection {
 3552                    id: selection.id,
 3553                    start: selection.start + delta,
 3554                    end: selection.end + delta,
 3555                    reversed: selection.reversed,
 3556                    goal: SelectionGoal::None,
 3557                })
 3558                .collect::<Vec<_>>();
 3559
 3560            let mut i = 0;
 3561            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3562                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3563                let start = map.buffer_snapshot.anchor_before(position);
 3564                let end = map.buffer_snapshot.anchor_after(position);
 3565                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3566                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3567                        Ordering::Less => i += 1,
 3568                        Ordering::Greater => break,
 3569                        Ordering::Equal => {
 3570                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 3571                                Ordering::Less => i += 1,
 3572                                Ordering::Equal => break,
 3573                                Ordering::Greater => break,
 3574                            }
 3575                        }
 3576                    }
 3577                }
 3578                this.autoclose_regions.insert(
 3579                    i,
 3580                    AutocloseRegion {
 3581                        selection_id,
 3582                        range: start..end,
 3583                        pair,
 3584                    },
 3585                );
 3586            }
 3587
 3588            let had_active_inline_completion = this.has_active_inline_completion();
 3589            this.change_selections_inner(Some(Autoscroll::fit()), false, window, cx, |s| {
 3590                s.select(new_selections)
 3591            });
 3592
 3593            if !bracket_inserted {
 3594                if let Some(on_type_format_task) =
 3595                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 3596                {
 3597                    on_type_format_task.detach_and_log_err(cx);
 3598                }
 3599            }
 3600
 3601            let editor_settings = EditorSettings::get_global(cx);
 3602            if bracket_inserted
 3603                && (editor_settings.auto_signature_help
 3604                    || editor_settings.show_signature_help_after_edits)
 3605            {
 3606                this.show_signature_help(&ShowSignatureHelp, window, cx);
 3607            }
 3608
 3609            let trigger_in_words =
 3610                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 3611            if this.hard_wrap.is_some() {
 3612                let latest: Range<Point> = this.selections.newest(cx).range();
 3613                if latest.is_empty()
 3614                    && this
 3615                        .buffer()
 3616                        .read(cx)
 3617                        .snapshot(cx)
 3618                        .line_len(MultiBufferRow(latest.start.row))
 3619                        == latest.start.column
 3620                {
 3621                    this.rewrap_impl(
 3622                        RewrapOptions {
 3623                            override_language_settings: true,
 3624                            preserve_existing_whitespace: true,
 3625                        },
 3626                        cx,
 3627                    )
 3628                }
 3629            }
 3630            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 3631            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 3632            this.refresh_inline_completion(true, false, window, cx);
 3633            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 3634        });
 3635    }
 3636
 3637    fn find_possible_emoji_shortcode_at_position(
 3638        snapshot: &MultiBufferSnapshot,
 3639        position: Point,
 3640    ) -> Option<String> {
 3641        let mut chars = Vec::new();
 3642        let mut found_colon = false;
 3643        for char in snapshot.reversed_chars_at(position).take(100) {
 3644            // Found a possible emoji shortcode in the middle of the buffer
 3645            if found_colon {
 3646                if char.is_whitespace() {
 3647                    chars.reverse();
 3648                    return Some(chars.iter().collect());
 3649                }
 3650                // If the previous character is not a whitespace, we are in the middle of a word
 3651                // and we only want to complete the shortcode if the word is made up of other emojis
 3652                let mut containing_word = String::new();
 3653                for ch in snapshot
 3654                    .reversed_chars_at(position)
 3655                    .skip(chars.len() + 1)
 3656                    .take(100)
 3657                {
 3658                    if ch.is_whitespace() {
 3659                        break;
 3660                    }
 3661                    containing_word.push(ch);
 3662                }
 3663                let containing_word = containing_word.chars().rev().collect::<String>();
 3664                if util::word_consists_of_emojis(containing_word.as_str()) {
 3665                    chars.reverse();
 3666                    return Some(chars.iter().collect());
 3667                }
 3668            }
 3669
 3670            if char.is_whitespace() || !char.is_ascii() {
 3671                return None;
 3672            }
 3673            if char == ':' {
 3674                found_colon = true;
 3675            } else {
 3676                chars.push(char);
 3677            }
 3678        }
 3679        // Found a possible emoji shortcode at the beginning of the buffer
 3680        chars.reverse();
 3681        Some(chars.iter().collect())
 3682    }
 3683
 3684    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 3685        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3686        self.transact(window, cx, |this, window, cx| {
 3687            let (edits, selection_fixup_info): (Vec<_>, Vec<_>) = {
 3688                let selections = this.selections.all::<usize>(cx);
 3689                let multi_buffer = this.buffer.read(cx);
 3690                let buffer = multi_buffer.snapshot(cx);
 3691                selections
 3692                    .iter()
 3693                    .map(|selection| {
 3694                        let start_point = selection.start.to_point(&buffer);
 3695                        let mut indent =
 3696                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 3697                        indent.len = cmp::min(indent.len, start_point.column);
 3698                        let start = selection.start;
 3699                        let end = selection.end;
 3700                        let selection_is_empty = start == end;
 3701                        let language_scope = buffer.language_scope_at(start);
 3702                        let (comment_delimiter, insert_extra_newline) = if let Some(language) =
 3703                            &language_scope
 3704                        {
 3705                            let insert_extra_newline =
 3706                                insert_extra_newline_brackets(&buffer, start..end, language)
 3707                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 3708
 3709                            // Comment extension on newline is allowed only for cursor selections
 3710                            let comment_delimiter = maybe!({
 3711                                if !selection_is_empty {
 3712                                    return None;
 3713                                }
 3714
 3715                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 3716                                    return None;
 3717                                }
 3718
 3719                                let delimiters = language.line_comment_prefixes();
 3720                                let max_len_of_delimiter =
 3721                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 3722                                let (snapshot, range) =
 3723                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 3724
 3725                                let mut index_of_first_non_whitespace = 0;
 3726                                let comment_candidate = snapshot
 3727                                    .chars_for_range(range)
 3728                                    .skip_while(|c| {
 3729                                        let should_skip = c.is_whitespace();
 3730                                        if should_skip {
 3731                                            index_of_first_non_whitespace += 1;
 3732                                        }
 3733                                        should_skip
 3734                                    })
 3735                                    .take(max_len_of_delimiter)
 3736                                    .collect::<String>();
 3737                                let comment_prefix = delimiters.iter().find(|comment_prefix| {
 3738                                    comment_candidate.starts_with(comment_prefix.as_ref())
 3739                                })?;
 3740                                let cursor_is_placed_after_comment_marker =
 3741                                    index_of_first_non_whitespace + comment_prefix.len()
 3742                                        <= start_point.column as usize;
 3743                                if cursor_is_placed_after_comment_marker {
 3744                                    Some(comment_prefix.clone())
 3745                                } else {
 3746                                    None
 3747                                }
 3748                            });
 3749                            (comment_delimiter, insert_extra_newline)
 3750                        } else {
 3751                            (None, false)
 3752                        };
 3753
 3754                        let capacity_for_delimiter = comment_delimiter
 3755                            .as_deref()
 3756                            .map(str::len)
 3757                            .unwrap_or_default();
 3758                        let mut new_text =
 3759                            String::with_capacity(1 + capacity_for_delimiter + indent.len as usize);
 3760                        new_text.push('\n');
 3761                        new_text.extend(indent.chars());
 3762                        if let Some(delimiter) = &comment_delimiter {
 3763                            new_text.push_str(delimiter);
 3764                        }
 3765                        if insert_extra_newline {
 3766                            new_text = new_text.repeat(2);
 3767                        }
 3768
 3769                        let anchor = buffer.anchor_after(end);
 3770                        let new_selection = selection.map(|_| anchor);
 3771                        (
 3772                            (start..end, new_text),
 3773                            (insert_extra_newline, new_selection),
 3774                        )
 3775                    })
 3776                    .unzip()
 3777            };
 3778
 3779            this.edit_with_autoindent(edits, cx);
 3780            let buffer = this.buffer.read(cx).snapshot(cx);
 3781            let new_selections = selection_fixup_info
 3782                .into_iter()
 3783                .map(|(extra_newline_inserted, new_selection)| {
 3784                    let mut cursor = new_selection.end.to_point(&buffer);
 3785                    if extra_newline_inserted {
 3786                        cursor.row -= 1;
 3787                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 3788                    }
 3789                    new_selection.map(|_| cursor)
 3790                })
 3791                .collect();
 3792
 3793            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 3794                s.select(new_selections)
 3795            });
 3796            this.refresh_inline_completion(true, false, window, cx);
 3797        });
 3798    }
 3799
 3800    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 3801        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3802
 3803        let buffer = self.buffer.read(cx);
 3804        let snapshot = buffer.snapshot(cx);
 3805
 3806        let mut edits = Vec::new();
 3807        let mut rows = Vec::new();
 3808
 3809        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 3810            let cursor = selection.head();
 3811            let row = cursor.row;
 3812
 3813            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 3814
 3815            let newline = "\n".to_string();
 3816            edits.push((start_of_line..start_of_line, newline));
 3817
 3818            rows.push(row + rows_inserted as u32);
 3819        }
 3820
 3821        self.transact(window, cx, |editor, window, cx| {
 3822            editor.edit(edits, cx);
 3823
 3824            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 3825                let mut index = 0;
 3826                s.move_cursors_with(|map, _, _| {
 3827                    let row = rows[index];
 3828                    index += 1;
 3829
 3830                    let point = Point::new(row, 0);
 3831                    let boundary = map.next_line_boundary(point).1;
 3832                    let clipped = map.clip_point(boundary, Bias::Left);
 3833
 3834                    (clipped, SelectionGoal::None)
 3835                });
 3836            });
 3837
 3838            let mut indent_edits = Vec::new();
 3839            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 3840            for row in rows {
 3841                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 3842                for (row, indent) in indents {
 3843                    if indent.len == 0 {
 3844                        continue;
 3845                    }
 3846
 3847                    let text = match indent.kind {
 3848                        IndentKind::Space => " ".repeat(indent.len as usize),
 3849                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 3850                    };
 3851                    let point = Point::new(row.0, 0);
 3852                    indent_edits.push((point..point, text));
 3853                }
 3854            }
 3855            editor.edit(indent_edits, cx);
 3856        });
 3857    }
 3858
 3859    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 3860        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3861
 3862        let buffer = self.buffer.read(cx);
 3863        let snapshot = buffer.snapshot(cx);
 3864
 3865        let mut edits = Vec::new();
 3866        let mut rows = Vec::new();
 3867        let mut rows_inserted = 0;
 3868
 3869        for selection in self.selections.all_adjusted(cx) {
 3870            let cursor = selection.head();
 3871            let row = cursor.row;
 3872
 3873            let point = Point::new(row + 1, 0);
 3874            let start_of_line = snapshot.clip_point(point, Bias::Left);
 3875
 3876            let newline = "\n".to_string();
 3877            edits.push((start_of_line..start_of_line, newline));
 3878
 3879            rows_inserted += 1;
 3880            rows.push(row + rows_inserted);
 3881        }
 3882
 3883        self.transact(window, cx, |editor, window, cx| {
 3884            editor.edit(edits, cx);
 3885
 3886            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 3887                let mut index = 0;
 3888                s.move_cursors_with(|map, _, _| {
 3889                    let row = rows[index];
 3890                    index += 1;
 3891
 3892                    let point = Point::new(row, 0);
 3893                    let boundary = map.next_line_boundary(point).1;
 3894                    let clipped = map.clip_point(boundary, Bias::Left);
 3895
 3896                    (clipped, SelectionGoal::None)
 3897                });
 3898            });
 3899
 3900            let mut indent_edits = Vec::new();
 3901            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 3902            for row in rows {
 3903                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 3904                for (row, indent) in indents {
 3905                    if indent.len == 0 {
 3906                        continue;
 3907                    }
 3908
 3909                    let text = match indent.kind {
 3910                        IndentKind::Space => " ".repeat(indent.len as usize),
 3911                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 3912                    };
 3913                    let point = Point::new(row.0, 0);
 3914                    indent_edits.push((point..point, text));
 3915                }
 3916            }
 3917            editor.edit(indent_edits, cx);
 3918        });
 3919    }
 3920
 3921    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3922        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 3923            original_indent_columns: Vec::new(),
 3924        });
 3925        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 3926    }
 3927
 3928    fn insert_with_autoindent_mode(
 3929        &mut self,
 3930        text: &str,
 3931        autoindent_mode: Option<AutoindentMode>,
 3932        window: &mut Window,
 3933        cx: &mut Context<Self>,
 3934    ) {
 3935        if self.read_only(cx) {
 3936            return;
 3937        }
 3938
 3939        let text: Arc<str> = text.into();
 3940        self.transact(window, cx, |this, window, cx| {
 3941            let old_selections = this.selections.all_adjusted(cx);
 3942            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 3943                let anchors = {
 3944                    let snapshot = buffer.read(cx);
 3945                    old_selections
 3946                        .iter()
 3947                        .map(|s| {
 3948                            let anchor = snapshot.anchor_after(s.head());
 3949                            s.map(|_| anchor)
 3950                        })
 3951                        .collect::<Vec<_>>()
 3952                };
 3953                buffer.edit(
 3954                    old_selections
 3955                        .iter()
 3956                        .map(|s| (s.start..s.end, text.clone())),
 3957                    autoindent_mode,
 3958                    cx,
 3959                );
 3960                anchors
 3961            });
 3962
 3963            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 3964                s.select_anchors(selection_anchors);
 3965            });
 3966
 3967            cx.notify();
 3968        });
 3969    }
 3970
 3971    fn trigger_completion_on_input(
 3972        &mut self,
 3973        text: &str,
 3974        trigger_in_words: bool,
 3975        window: &mut Window,
 3976        cx: &mut Context<Self>,
 3977    ) {
 3978        let ignore_completion_provider = self
 3979            .context_menu
 3980            .borrow()
 3981            .as_ref()
 3982            .map(|menu| match menu {
 3983                CodeContextMenu::Completions(completions_menu) => {
 3984                    completions_menu.ignore_completion_provider
 3985                }
 3986                CodeContextMenu::CodeActions(_) => false,
 3987            })
 3988            .unwrap_or(false);
 3989
 3990        if ignore_completion_provider {
 3991            self.show_word_completions(&ShowWordCompletions, window, cx);
 3992        } else if self.is_completion_trigger(text, trigger_in_words, cx) {
 3993            self.show_completions(
 3994                &ShowCompletions {
 3995                    trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 3996                },
 3997                window,
 3998                cx,
 3999            );
 4000        } else {
 4001            self.hide_context_menu(window, cx);
 4002        }
 4003    }
 4004
 4005    fn is_completion_trigger(
 4006        &self,
 4007        text: &str,
 4008        trigger_in_words: bool,
 4009        cx: &mut Context<Self>,
 4010    ) -> bool {
 4011        let position = self.selections.newest_anchor().head();
 4012        let multibuffer = self.buffer.read(cx);
 4013        let Some(buffer) = position
 4014            .buffer_id
 4015            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4016        else {
 4017            return false;
 4018        };
 4019
 4020        if let Some(completion_provider) = &self.completion_provider {
 4021            completion_provider.is_completion_trigger(
 4022                &buffer,
 4023                position.text_anchor,
 4024                text,
 4025                trigger_in_words,
 4026                cx,
 4027            )
 4028        } else {
 4029            false
 4030        }
 4031    }
 4032
 4033    /// If any empty selections is touching the start of its innermost containing autoclose
 4034    /// region, expand it to select the brackets.
 4035    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4036        let selections = self.selections.all::<usize>(cx);
 4037        let buffer = self.buffer.read(cx).read(cx);
 4038        let new_selections = self
 4039            .selections_with_autoclose_regions(selections, &buffer)
 4040            .map(|(mut selection, region)| {
 4041                if !selection.is_empty() {
 4042                    return selection;
 4043                }
 4044
 4045                if let Some(region) = region {
 4046                    let mut range = region.range.to_offset(&buffer);
 4047                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4048                        range.start -= region.pair.start.len();
 4049                        if buffer.contains_str_at(range.start, &region.pair.start)
 4050                            && buffer.contains_str_at(range.end, &region.pair.end)
 4051                        {
 4052                            range.end += region.pair.end.len();
 4053                            selection.start = range.start;
 4054                            selection.end = range.end;
 4055
 4056                            return selection;
 4057                        }
 4058                    }
 4059                }
 4060
 4061                let always_treat_brackets_as_autoclosed = buffer
 4062                    .language_settings_at(selection.start, cx)
 4063                    .always_treat_brackets_as_autoclosed;
 4064
 4065                if !always_treat_brackets_as_autoclosed {
 4066                    return selection;
 4067                }
 4068
 4069                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4070                    for (pair, enabled) in scope.brackets() {
 4071                        if !enabled || !pair.close {
 4072                            continue;
 4073                        }
 4074
 4075                        if buffer.contains_str_at(selection.start, &pair.end) {
 4076                            let pair_start_len = pair.start.len();
 4077                            if buffer.contains_str_at(
 4078                                selection.start.saturating_sub(pair_start_len),
 4079                                &pair.start,
 4080                            ) {
 4081                                selection.start -= pair_start_len;
 4082                                selection.end += pair.end.len();
 4083
 4084                                return selection;
 4085                            }
 4086                        }
 4087                    }
 4088                }
 4089
 4090                selection
 4091            })
 4092            .collect();
 4093
 4094        drop(buffer);
 4095        self.change_selections(None, window, cx, |selections| {
 4096            selections.select(new_selections)
 4097        });
 4098    }
 4099
 4100    /// Iterate the given selections, and for each one, find the smallest surrounding
 4101    /// autoclose region. This uses the ordering of the selections and the autoclose
 4102    /// regions to avoid repeated comparisons.
 4103    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4104        &'a self,
 4105        selections: impl IntoIterator<Item = Selection<D>>,
 4106        buffer: &'a MultiBufferSnapshot,
 4107    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4108        let mut i = 0;
 4109        let mut regions = self.autoclose_regions.as_slice();
 4110        selections.into_iter().map(move |selection| {
 4111            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4112
 4113            let mut enclosing = None;
 4114            while let Some(pair_state) = regions.get(i) {
 4115                if pair_state.range.end.to_offset(buffer) < range.start {
 4116                    regions = &regions[i + 1..];
 4117                    i = 0;
 4118                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4119                    break;
 4120                } else {
 4121                    if pair_state.selection_id == selection.id {
 4122                        enclosing = Some(pair_state);
 4123                    }
 4124                    i += 1;
 4125                }
 4126            }
 4127
 4128            (selection, enclosing)
 4129        })
 4130    }
 4131
 4132    /// Remove any autoclose regions that no longer contain their selection.
 4133    fn invalidate_autoclose_regions(
 4134        &mut self,
 4135        mut selections: &[Selection<Anchor>],
 4136        buffer: &MultiBufferSnapshot,
 4137    ) {
 4138        self.autoclose_regions.retain(|state| {
 4139            let mut i = 0;
 4140            while let Some(selection) = selections.get(i) {
 4141                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4142                    selections = &selections[1..];
 4143                    continue;
 4144                }
 4145                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4146                    break;
 4147                }
 4148                if selection.id == state.selection_id {
 4149                    return true;
 4150                } else {
 4151                    i += 1;
 4152                }
 4153            }
 4154            false
 4155        });
 4156    }
 4157
 4158    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4159        let offset = position.to_offset(buffer);
 4160        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4161        if offset > word_range.start && kind == Some(CharKind::Word) {
 4162            Some(
 4163                buffer
 4164                    .text_for_range(word_range.start..offset)
 4165                    .collect::<String>(),
 4166            )
 4167        } else {
 4168            None
 4169        }
 4170    }
 4171
 4172    pub fn toggle_inlay_hints(
 4173        &mut self,
 4174        _: &ToggleInlayHints,
 4175        _: &mut Window,
 4176        cx: &mut Context<Self>,
 4177    ) {
 4178        self.refresh_inlay_hints(
 4179            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4180            cx,
 4181        );
 4182    }
 4183
 4184    pub fn inlay_hints_enabled(&self) -> bool {
 4185        self.inlay_hint_cache.enabled
 4186    }
 4187
 4188    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4189        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4190            return;
 4191        }
 4192
 4193        let reason_description = reason.description();
 4194        let ignore_debounce = matches!(
 4195            reason,
 4196            InlayHintRefreshReason::SettingsChange(_)
 4197                | InlayHintRefreshReason::Toggle(_)
 4198                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4199                | InlayHintRefreshReason::ModifiersChanged(_)
 4200        );
 4201        let (invalidate_cache, required_languages) = match reason {
 4202            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4203                match self.inlay_hint_cache.modifiers_override(enabled) {
 4204                    Some(enabled) => {
 4205                        if enabled {
 4206                            (InvalidationStrategy::RefreshRequested, None)
 4207                        } else {
 4208                            self.splice_inlays(
 4209                                &self
 4210                                    .visible_inlay_hints(cx)
 4211                                    .iter()
 4212                                    .map(|inlay| inlay.id)
 4213                                    .collect::<Vec<InlayId>>(),
 4214                                Vec::new(),
 4215                                cx,
 4216                            );
 4217                            return;
 4218                        }
 4219                    }
 4220                    None => return,
 4221                }
 4222            }
 4223            InlayHintRefreshReason::Toggle(enabled) => {
 4224                if self.inlay_hint_cache.toggle(enabled) {
 4225                    if enabled {
 4226                        (InvalidationStrategy::RefreshRequested, None)
 4227                    } else {
 4228                        self.splice_inlays(
 4229                            &self
 4230                                .visible_inlay_hints(cx)
 4231                                .iter()
 4232                                .map(|inlay| inlay.id)
 4233                                .collect::<Vec<InlayId>>(),
 4234                            Vec::new(),
 4235                            cx,
 4236                        );
 4237                        return;
 4238                    }
 4239                } else {
 4240                    return;
 4241                }
 4242            }
 4243            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4244                match self.inlay_hint_cache.update_settings(
 4245                    &self.buffer,
 4246                    new_settings,
 4247                    self.visible_inlay_hints(cx),
 4248                    cx,
 4249                ) {
 4250                    ControlFlow::Break(Some(InlaySplice {
 4251                        to_remove,
 4252                        to_insert,
 4253                    })) => {
 4254                        self.splice_inlays(&to_remove, to_insert, cx);
 4255                        return;
 4256                    }
 4257                    ControlFlow::Break(None) => return,
 4258                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4259                }
 4260            }
 4261            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4262                if let Some(InlaySplice {
 4263                    to_remove,
 4264                    to_insert,
 4265                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4266                {
 4267                    self.splice_inlays(&to_remove, to_insert, cx);
 4268                }
 4269                self.display_map.update(cx, |display_map, _| {
 4270                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4271                });
 4272                return;
 4273            }
 4274            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4275            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4276                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4277            }
 4278            InlayHintRefreshReason::RefreshRequested => {
 4279                (InvalidationStrategy::RefreshRequested, None)
 4280            }
 4281        };
 4282
 4283        if let Some(InlaySplice {
 4284            to_remove,
 4285            to_insert,
 4286        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4287            reason_description,
 4288            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4289            invalidate_cache,
 4290            ignore_debounce,
 4291            cx,
 4292        ) {
 4293            self.splice_inlays(&to_remove, to_insert, cx);
 4294        }
 4295    }
 4296
 4297    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4298        self.display_map
 4299            .read(cx)
 4300            .current_inlays()
 4301            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4302            .cloned()
 4303            .collect()
 4304    }
 4305
 4306    pub fn excerpts_for_inlay_hints_query(
 4307        &self,
 4308        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4309        cx: &mut Context<Editor>,
 4310    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4311        let Some(project) = self.project.as_ref() else {
 4312            return HashMap::default();
 4313        };
 4314        let project = project.read(cx);
 4315        let multi_buffer = self.buffer().read(cx);
 4316        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4317        let multi_buffer_visible_start = self
 4318            .scroll_manager
 4319            .anchor()
 4320            .anchor
 4321            .to_point(&multi_buffer_snapshot);
 4322        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4323            multi_buffer_visible_start
 4324                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4325            Bias::Left,
 4326        );
 4327        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4328        multi_buffer_snapshot
 4329            .range_to_buffer_ranges(multi_buffer_visible_range)
 4330            .into_iter()
 4331            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4332            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4333                let buffer_file = project::File::from_dyn(buffer.file())?;
 4334                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4335                let worktree_entry = buffer_worktree
 4336                    .read(cx)
 4337                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4338                if worktree_entry.is_ignored {
 4339                    return None;
 4340                }
 4341
 4342                let language = buffer.language()?;
 4343                if let Some(restrict_to_languages) = restrict_to_languages {
 4344                    if !restrict_to_languages.contains(language) {
 4345                        return None;
 4346                    }
 4347                }
 4348                Some((
 4349                    excerpt_id,
 4350                    (
 4351                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4352                        buffer.version().clone(),
 4353                        excerpt_visible_range,
 4354                    ),
 4355                ))
 4356            })
 4357            .collect()
 4358    }
 4359
 4360    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4361        TextLayoutDetails {
 4362            text_system: window.text_system().clone(),
 4363            editor_style: self.style.clone().unwrap(),
 4364            rem_size: window.rem_size(),
 4365            scroll_anchor: self.scroll_manager.anchor(),
 4366            visible_rows: self.visible_line_count(),
 4367            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4368        }
 4369    }
 4370
 4371    pub fn splice_inlays(
 4372        &self,
 4373        to_remove: &[InlayId],
 4374        to_insert: Vec<Inlay>,
 4375        cx: &mut Context<Self>,
 4376    ) {
 4377        self.display_map.update(cx, |display_map, cx| {
 4378            display_map.splice_inlays(to_remove, to_insert, cx)
 4379        });
 4380        cx.notify();
 4381    }
 4382
 4383    fn trigger_on_type_formatting(
 4384        &self,
 4385        input: String,
 4386        window: &mut Window,
 4387        cx: &mut Context<Self>,
 4388    ) -> Option<Task<Result<()>>> {
 4389        if input.len() != 1 {
 4390            return None;
 4391        }
 4392
 4393        let project = self.project.as_ref()?;
 4394        let position = self.selections.newest_anchor().head();
 4395        let (buffer, buffer_position) = self
 4396            .buffer
 4397            .read(cx)
 4398            .text_anchor_for_position(position, cx)?;
 4399
 4400        let settings = language_settings::language_settings(
 4401            buffer
 4402                .read(cx)
 4403                .language_at(buffer_position)
 4404                .map(|l| l.name()),
 4405            buffer.read(cx).file(),
 4406            cx,
 4407        );
 4408        if !settings.use_on_type_format {
 4409            return None;
 4410        }
 4411
 4412        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 4413        // hence we do LSP request & edit on host side only — add formats to host's history.
 4414        let push_to_lsp_host_history = true;
 4415        // If this is not the host, append its history with new edits.
 4416        let push_to_client_history = project.read(cx).is_via_collab();
 4417
 4418        let on_type_formatting = project.update(cx, |project, cx| {
 4419            project.on_type_format(
 4420                buffer.clone(),
 4421                buffer_position,
 4422                input,
 4423                push_to_lsp_host_history,
 4424                cx,
 4425            )
 4426        });
 4427        Some(cx.spawn_in(window, async move |editor, cx| {
 4428            if let Some(transaction) = on_type_formatting.await? {
 4429                if push_to_client_history {
 4430                    buffer
 4431                        .update(cx, |buffer, _| {
 4432                            buffer.push_transaction(transaction, Instant::now());
 4433                            buffer.finalize_last_transaction();
 4434                        })
 4435                        .ok();
 4436                }
 4437                editor.update(cx, |editor, cx| {
 4438                    editor.refresh_document_highlights(cx);
 4439                })?;
 4440            }
 4441            Ok(())
 4442        }))
 4443    }
 4444
 4445    pub fn show_word_completions(
 4446        &mut self,
 4447        _: &ShowWordCompletions,
 4448        window: &mut Window,
 4449        cx: &mut Context<Self>,
 4450    ) {
 4451        self.open_completions_menu(true, None, window, cx);
 4452    }
 4453
 4454    pub fn show_completions(
 4455        &mut self,
 4456        options: &ShowCompletions,
 4457        window: &mut Window,
 4458        cx: &mut Context<Self>,
 4459    ) {
 4460        self.open_completions_menu(false, options.trigger.as_deref(), window, cx);
 4461    }
 4462
 4463    fn open_completions_menu(
 4464        &mut self,
 4465        ignore_completion_provider: bool,
 4466        trigger: Option<&str>,
 4467        window: &mut Window,
 4468        cx: &mut Context<Self>,
 4469    ) {
 4470        if self.pending_rename.is_some() {
 4471            return;
 4472        }
 4473        if !self.snippet_stack.is_empty() && self.context_menu.borrow().as_ref().is_some() {
 4474            return;
 4475        }
 4476
 4477        let position = self.selections.newest_anchor().head();
 4478        if position.diff_base_anchor.is_some() {
 4479            return;
 4480        }
 4481        let (buffer, buffer_position) =
 4482            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 4483                output
 4484            } else {
 4485                return;
 4486            };
 4487        let buffer_snapshot = buffer.read(cx).snapshot();
 4488        let show_completion_documentation = buffer_snapshot
 4489            .settings_at(buffer_position, cx)
 4490            .show_completion_documentation;
 4491
 4492        let query = Self::completion_query(&self.buffer.read(cx).read(cx), position);
 4493
 4494        let trigger_kind = match trigger {
 4495            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 4496                CompletionTriggerKind::TRIGGER_CHARACTER
 4497            }
 4498            _ => CompletionTriggerKind::INVOKED,
 4499        };
 4500        let completion_context = CompletionContext {
 4501            trigger_character: trigger.and_then(|trigger| {
 4502                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 4503                    Some(String::from(trigger))
 4504                } else {
 4505                    None
 4506                }
 4507            }),
 4508            trigger_kind,
 4509        };
 4510
 4511        let (old_range, word_kind) = buffer_snapshot.surrounding_word(buffer_position);
 4512        let (old_range, word_to_exclude) = if word_kind == Some(CharKind::Word) {
 4513            let word_to_exclude = buffer_snapshot
 4514                .text_for_range(old_range.clone())
 4515                .collect::<String>();
 4516            (
 4517                buffer_snapshot.anchor_before(old_range.start)
 4518                    ..buffer_snapshot.anchor_after(old_range.end),
 4519                Some(word_to_exclude),
 4520            )
 4521        } else {
 4522            (buffer_position..buffer_position, None)
 4523        };
 4524
 4525        let completion_settings = language_settings(
 4526            buffer_snapshot
 4527                .language_at(buffer_position)
 4528                .map(|language| language.name()),
 4529            buffer_snapshot.file(),
 4530            cx,
 4531        )
 4532        .completions;
 4533
 4534        // The document can be large, so stay in reasonable bounds when searching for words,
 4535        // otherwise completion pop-up might be slow to appear.
 4536        const WORD_LOOKUP_ROWS: u32 = 5_000;
 4537        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 4538        let min_word_search = buffer_snapshot.clip_point(
 4539            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 4540            Bias::Left,
 4541        );
 4542        let max_word_search = buffer_snapshot.clip_point(
 4543            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 4544            Bias::Right,
 4545        );
 4546        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 4547            ..buffer_snapshot.point_to_offset(max_word_search);
 4548
 4549        let provider = self
 4550            .completion_provider
 4551            .as_ref()
 4552            .filter(|_| !ignore_completion_provider);
 4553        let skip_digits = query
 4554            .as_ref()
 4555            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 4556
 4557        let (mut words, provided_completions) = match provider {
 4558            Some(provider) => {
 4559                let completions = provider.completions(
 4560                    position.excerpt_id,
 4561                    &buffer,
 4562                    buffer_position,
 4563                    completion_context,
 4564                    window,
 4565                    cx,
 4566                );
 4567
 4568                let words = match completion_settings.words {
 4569                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 4570                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 4571                        .background_spawn(async move {
 4572                            buffer_snapshot.words_in_range(WordsQuery {
 4573                                fuzzy_contents: None,
 4574                                range: word_search_range,
 4575                                skip_digits,
 4576                            })
 4577                        }),
 4578                };
 4579
 4580                (words, completions)
 4581            }
 4582            None => (
 4583                cx.background_spawn(async move {
 4584                    buffer_snapshot.words_in_range(WordsQuery {
 4585                        fuzzy_contents: None,
 4586                        range: word_search_range,
 4587                        skip_digits,
 4588                    })
 4589                }),
 4590                Task::ready(Ok(None)),
 4591            ),
 4592        };
 4593
 4594        let sort_completions = provider
 4595            .as_ref()
 4596            .map_or(false, |provider| provider.sort_completions());
 4597
 4598        let filter_completions = provider
 4599            .as_ref()
 4600            .map_or(true, |provider| provider.filter_completions());
 4601
 4602        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 4603
 4604        let id = post_inc(&mut self.next_completion_id);
 4605        let task = cx.spawn_in(window, async move |editor, cx| {
 4606            async move {
 4607                editor.update(cx, |this, _| {
 4608                    this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 4609                })?;
 4610
 4611                let mut completions = Vec::new();
 4612                if let Some(provided_completions) = provided_completions.await.log_err().flatten() {
 4613                    completions.extend(provided_completions);
 4614                    if completion_settings.words == WordsCompletionMode::Fallback {
 4615                        words = Task::ready(BTreeMap::default());
 4616                    }
 4617                }
 4618
 4619                let mut words = words.await;
 4620                if let Some(word_to_exclude) = &word_to_exclude {
 4621                    words.remove(word_to_exclude);
 4622                }
 4623                for lsp_completion in &completions {
 4624                    words.remove(&lsp_completion.new_text);
 4625                }
 4626                completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 4627                    replace_range: old_range.clone(),
 4628                    new_text: word.clone(),
 4629                    label: CodeLabel::plain(word, None),
 4630                    icon_path: None,
 4631                    documentation: None,
 4632                    source: CompletionSource::BufferWord {
 4633                        word_range,
 4634                        resolved: false,
 4635                    },
 4636                    insert_text_mode: Some(InsertTextMode::AS_IS),
 4637                    confirm: None,
 4638                }));
 4639
 4640                let menu = if completions.is_empty() {
 4641                    None
 4642                } else {
 4643                    let mut menu = CompletionsMenu::new(
 4644                        id,
 4645                        sort_completions,
 4646                        show_completion_documentation,
 4647                        ignore_completion_provider,
 4648                        position,
 4649                        buffer.clone(),
 4650                        completions.into(),
 4651                        snippet_sort_order,
 4652                    );
 4653
 4654                    menu.filter(
 4655                        if filter_completions {
 4656                            query.as_deref()
 4657                        } else {
 4658                            None
 4659                        },
 4660                        cx.background_executor().clone(),
 4661                    )
 4662                    .await;
 4663
 4664                    menu.visible().then_some(menu)
 4665                };
 4666
 4667                editor.update_in(cx, |editor, window, cx| {
 4668                    match editor.context_menu.borrow().as_ref() {
 4669                        None => {}
 4670                        Some(CodeContextMenu::Completions(prev_menu)) => {
 4671                            if prev_menu.id > id {
 4672                                return;
 4673                            }
 4674                        }
 4675                        _ => return,
 4676                    }
 4677
 4678                    if editor.focus_handle.is_focused(window) && menu.is_some() {
 4679                        let mut menu = menu.unwrap();
 4680                        menu.resolve_visible_completions(editor.completion_provider.as_deref(), cx);
 4681
 4682                        *editor.context_menu.borrow_mut() =
 4683                            Some(CodeContextMenu::Completions(menu));
 4684
 4685                        if editor.show_edit_predictions_in_menu() {
 4686                            editor.update_visible_inline_completion(window, cx);
 4687                        } else {
 4688                            editor.discard_inline_completion(false, cx);
 4689                        }
 4690
 4691                        cx.notify();
 4692                    } else if editor.completion_tasks.len() <= 1 {
 4693                        // If there are no more completion tasks and the last menu was
 4694                        // empty, we should hide it.
 4695                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 4696                        // If it was already hidden and we don't show inline
 4697                        // completions in the menu, we should also show the
 4698                        // inline-completion when available.
 4699                        if was_hidden && editor.show_edit_predictions_in_menu() {
 4700                            editor.update_visible_inline_completion(window, cx);
 4701                        }
 4702                    }
 4703                })?;
 4704
 4705                anyhow::Ok(())
 4706            }
 4707            .log_err()
 4708            .await
 4709        });
 4710
 4711        self.completion_tasks.push((id, task));
 4712    }
 4713
 4714    #[cfg(feature = "test-support")]
 4715    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 4716        let menu = self.context_menu.borrow();
 4717        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 4718            let completions = menu.completions.borrow();
 4719            Some(completions.to_vec())
 4720        } else {
 4721            None
 4722        }
 4723    }
 4724
 4725    pub fn confirm_completion(
 4726        &mut self,
 4727        action: &ConfirmCompletion,
 4728        window: &mut Window,
 4729        cx: &mut Context<Self>,
 4730    ) -> Option<Task<Result<()>>> {
 4731        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4732        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 4733    }
 4734
 4735    pub fn confirm_completion_insert(
 4736        &mut self,
 4737        _: &ConfirmCompletionInsert,
 4738        window: &mut Window,
 4739        cx: &mut Context<Self>,
 4740    ) -> Option<Task<Result<()>>> {
 4741        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4742        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 4743    }
 4744
 4745    pub fn confirm_completion_replace(
 4746        &mut self,
 4747        _: &ConfirmCompletionReplace,
 4748        window: &mut Window,
 4749        cx: &mut Context<Self>,
 4750    ) -> Option<Task<Result<()>>> {
 4751        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4752        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 4753    }
 4754
 4755    pub fn compose_completion(
 4756        &mut self,
 4757        action: &ComposeCompletion,
 4758        window: &mut Window,
 4759        cx: &mut Context<Self>,
 4760    ) -> Option<Task<Result<()>>> {
 4761        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4762        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 4763    }
 4764
 4765    fn do_completion(
 4766        &mut self,
 4767        item_ix: Option<usize>,
 4768        intent: CompletionIntent,
 4769        window: &mut Window,
 4770        cx: &mut Context<Editor>,
 4771    ) -> Option<Task<Result<()>>> {
 4772        use language::ToOffset as _;
 4773
 4774        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 4775        else {
 4776            return None;
 4777        };
 4778
 4779        let candidate_id = {
 4780            let entries = completions_menu.entries.borrow();
 4781            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 4782            if self.show_edit_predictions_in_menu() {
 4783                self.discard_inline_completion(true, cx);
 4784            }
 4785            mat.candidate_id
 4786        };
 4787
 4788        let buffer_handle = completions_menu.buffer;
 4789        let completion = completions_menu
 4790            .completions
 4791            .borrow()
 4792            .get(candidate_id)?
 4793            .clone();
 4794        cx.stop_propagation();
 4795
 4796        let snippet;
 4797        let new_text;
 4798        if completion.is_snippet() {
 4799            snippet = Some(Snippet::parse(&completion.new_text).log_err()?);
 4800            new_text = snippet.as_ref().unwrap().text.clone();
 4801        } else {
 4802            snippet = None;
 4803            new_text = completion.new_text.clone();
 4804        };
 4805
 4806        let replace_range = choose_completion_range(&completion, intent, &buffer_handle, cx);
 4807        let buffer = buffer_handle.read(cx);
 4808        let snapshot = self.buffer.read(cx).snapshot(cx);
 4809        let replace_range_multibuffer = {
 4810            let excerpt = snapshot
 4811                .excerpt_containing(self.selections.newest_anchor().range())
 4812                .unwrap();
 4813            let multibuffer_anchor = snapshot
 4814                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 4815                .unwrap()
 4816                ..snapshot
 4817                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 4818                    .unwrap();
 4819            multibuffer_anchor.start.to_offset(&snapshot)
 4820                ..multibuffer_anchor.end.to_offset(&snapshot)
 4821        };
 4822        let newest_anchor = self.selections.newest_anchor();
 4823        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 4824            return None;
 4825        }
 4826
 4827        let old_text = buffer
 4828            .text_for_range(replace_range.clone())
 4829            .collect::<String>();
 4830        let lookbehind = newest_anchor
 4831            .start
 4832            .text_anchor
 4833            .to_offset(buffer)
 4834            .saturating_sub(replace_range.start);
 4835        let lookahead = replace_range
 4836            .end
 4837            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 4838        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 4839        let suffix = &old_text[lookbehind.min(old_text.len())..];
 4840
 4841        let selections = self.selections.all::<usize>(cx);
 4842        let mut ranges = Vec::new();
 4843        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4844
 4845        for selection in &selections {
 4846            let range = if selection.id == newest_anchor.id {
 4847                replace_range_multibuffer.clone()
 4848            } else {
 4849                let mut range = selection.range();
 4850
 4851                // if prefix is present, don't duplicate it
 4852                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 4853                    range.start = range.start.saturating_sub(lookbehind);
 4854
 4855                    // if suffix is also present, mimic the newest cursor and replace it
 4856                    if selection.id != newest_anchor.id
 4857                        && snapshot.contains_str_at(range.end, suffix)
 4858                    {
 4859                        range.end += lookahead;
 4860                    }
 4861                }
 4862                range
 4863            };
 4864
 4865            ranges.push(range);
 4866
 4867            if !self.linked_edit_ranges.is_empty() {
 4868                let start_anchor = snapshot.anchor_before(selection.head());
 4869                let end_anchor = snapshot.anchor_after(selection.tail());
 4870                if let Some(ranges) = self
 4871                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 4872                {
 4873                    for (buffer, edits) in ranges {
 4874                        linked_edits
 4875                            .entry(buffer.clone())
 4876                            .or_default()
 4877                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 4878                    }
 4879                }
 4880            }
 4881        }
 4882
 4883        cx.emit(EditorEvent::InputHandled {
 4884            utf16_range_to_replace: None,
 4885            text: new_text.clone().into(),
 4886        });
 4887
 4888        self.transact(window, cx, |this, window, cx| {
 4889            if let Some(mut snippet) = snippet {
 4890                snippet.text = new_text.to_string();
 4891                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 4892            } else {
 4893                this.buffer.update(cx, |buffer, cx| {
 4894                    let auto_indent = match completion.insert_text_mode {
 4895                        Some(InsertTextMode::AS_IS) => None,
 4896                        _ => this.autoindent_mode.clone(),
 4897                    };
 4898                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 4899                    buffer.edit(edits, auto_indent, cx);
 4900                });
 4901            }
 4902            for (buffer, edits) in linked_edits {
 4903                buffer.update(cx, |buffer, cx| {
 4904                    let snapshot = buffer.snapshot();
 4905                    let edits = edits
 4906                        .into_iter()
 4907                        .map(|(range, text)| {
 4908                            use text::ToPoint as TP;
 4909                            let end_point = TP::to_point(&range.end, &snapshot);
 4910                            let start_point = TP::to_point(&range.start, &snapshot);
 4911                            (start_point..end_point, text)
 4912                        })
 4913                        .sorted_by_key(|(range, _)| range.start);
 4914                    buffer.edit(edits, None, cx);
 4915                })
 4916            }
 4917
 4918            this.refresh_inline_completion(true, false, window, cx);
 4919        });
 4920
 4921        let show_new_completions_on_confirm = completion
 4922            .confirm
 4923            .as_ref()
 4924            .map_or(false, |confirm| confirm(intent, window, cx));
 4925        if show_new_completions_on_confirm {
 4926            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 4927        }
 4928
 4929        let provider = self.completion_provider.as_ref()?;
 4930        drop(completion);
 4931        let apply_edits = provider.apply_additional_edits_for_completion(
 4932            buffer_handle,
 4933            completions_menu.completions.clone(),
 4934            candidate_id,
 4935            true,
 4936            cx,
 4937        );
 4938
 4939        let editor_settings = EditorSettings::get_global(cx);
 4940        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 4941            // After the code completion is finished, users often want to know what signatures are needed.
 4942            // so we should automatically call signature_help
 4943            self.show_signature_help(&ShowSignatureHelp, window, cx);
 4944        }
 4945
 4946        Some(cx.foreground_executor().spawn(async move {
 4947            apply_edits.await?;
 4948            Ok(())
 4949        }))
 4950    }
 4951
 4952    pub fn toggle_code_actions(
 4953        &mut self,
 4954        action: &ToggleCodeActions,
 4955        window: &mut Window,
 4956        cx: &mut Context<Self>,
 4957    ) {
 4958        let mut context_menu = self.context_menu.borrow_mut();
 4959        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 4960            if code_actions.deployed_from_indicator == action.deployed_from_indicator {
 4961                // Toggle if we're selecting the same one
 4962                *context_menu = None;
 4963                cx.notify();
 4964                return;
 4965            } else {
 4966                // Otherwise, clear it and start a new one
 4967                *context_menu = None;
 4968                cx.notify();
 4969            }
 4970        }
 4971        drop(context_menu);
 4972        let snapshot = self.snapshot(window, cx);
 4973        let deployed_from_indicator = action.deployed_from_indicator;
 4974        let mut task = self.code_actions_task.take();
 4975        let action = action.clone();
 4976        cx.spawn_in(window, async move |editor, cx| {
 4977            while let Some(prev_task) = task {
 4978                prev_task.await.log_err();
 4979                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
 4980            }
 4981
 4982            let spawned_test_task = editor.update_in(cx, |editor, window, cx| {
 4983                if editor.focus_handle.is_focused(window) {
 4984                    let multibuffer_point = action
 4985                        .deployed_from_indicator
 4986                        .map(|row| DisplayPoint::new(row, 0).to_point(&snapshot))
 4987                        .unwrap_or_else(|| editor.selections.newest::<Point>(cx).head());
 4988                    let (buffer, buffer_row) = snapshot
 4989                        .buffer_snapshot
 4990                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 4991                        .and_then(|(buffer_snapshot, range)| {
 4992                            editor
 4993                                .buffer
 4994                                .read(cx)
 4995                                .buffer(buffer_snapshot.remote_id())
 4996                                .map(|buffer| (buffer, range.start.row))
 4997                        })?;
 4998                    let (_, code_actions) = editor
 4999                        .available_code_actions
 5000                        .clone()
 5001                        .and_then(|(location, code_actions)| {
 5002                            let snapshot = location.buffer.read(cx).snapshot();
 5003                            let point_range = location.range.to_point(&snapshot);
 5004                            let point_range = point_range.start.row..=point_range.end.row;
 5005                            if point_range.contains(&buffer_row) {
 5006                                Some((location, code_actions))
 5007                            } else {
 5008                                None
 5009                            }
 5010                        })
 5011                        .unzip();
 5012                    let buffer_id = buffer.read(cx).remote_id();
 5013                    let tasks = editor
 5014                        .tasks
 5015                        .get(&(buffer_id, buffer_row))
 5016                        .map(|t| Arc::new(t.to_owned()));
 5017                    if tasks.is_none() && code_actions.is_none() {
 5018                        return None;
 5019                    }
 5020
 5021                    editor.completion_tasks.clear();
 5022                    editor.discard_inline_completion(false, cx);
 5023                    let task_context =
 5024                        tasks
 5025                            .as_ref()
 5026                            .zip(editor.project.clone())
 5027                            .map(|(tasks, project)| {
 5028                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 5029                            });
 5030
 5031                    let debugger_flag = cx.has_flag::<DebuggerFeatureFlag>();
 5032
 5033                    Some(cx.spawn_in(window, async move |editor, cx| {
 5034                        let task_context = match task_context {
 5035                            Some(task_context) => task_context.await,
 5036                            None => None,
 5037                        };
 5038                        let resolved_tasks =
 5039                            tasks
 5040                                .zip(task_context)
 5041                                .map(|(tasks, task_context)| ResolvedTasks {
 5042                                    templates: tasks.resolve(&task_context).collect(),
 5043                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5044                                        multibuffer_point.row,
 5045                                        tasks.column,
 5046                                    )),
 5047                                });
 5048                        let spawn_straight_away = resolved_tasks.as_ref().map_or(false, |tasks| {
 5049                            tasks
 5050                                .templates
 5051                                .iter()
 5052                                .filter(|task| {
 5053                                    if matches!(task.1.task_type(), task::TaskType::Debug(_)) {
 5054                                        debugger_flag
 5055                                    } else {
 5056                                        true
 5057                                    }
 5058                                })
 5059                                .count()
 5060                                == 1
 5061                        }) && code_actions
 5062                            .as_ref()
 5063                            .map_or(true, |actions| actions.is_empty());
 5064                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
 5065                            *editor.context_menu.borrow_mut() =
 5066                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5067                                    buffer,
 5068                                    actions: CodeActionContents::new(
 5069                                        resolved_tasks,
 5070                                        code_actions,
 5071                                        cx,
 5072                                    ),
 5073                                    selected_item: Default::default(),
 5074                                    scroll_handle: UniformListScrollHandle::default(),
 5075                                    deployed_from_indicator,
 5076                                }));
 5077                            if spawn_straight_away {
 5078                                if let Some(task) = editor.confirm_code_action(
 5079                                    &ConfirmCodeAction { item_ix: Some(0) },
 5080                                    window,
 5081                                    cx,
 5082                                ) {
 5083                                    cx.notify();
 5084                                    return task;
 5085                                }
 5086                            }
 5087                            cx.notify();
 5088                            Task::ready(Ok(()))
 5089                        }) {
 5090                            task.await
 5091                        } else {
 5092                            Ok(())
 5093                        }
 5094                    }))
 5095                } else {
 5096                    Some(Task::ready(Ok(())))
 5097                }
 5098            })?;
 5099            if let Some(task) = spawned_test_task {
 5100                task.await?;
 5101            }
 5102
 5103            Ok::<_, anyhow::Error>(())
 5104        })
 5105        .detach_and_log_err(cx);
 5106    }
 5107
 5108    pub fn confirm_code_action(
 5109        &mut self,
 5110        action: &ConfirmCodeAction,
 5111        window: &mut Window,
 5112        cx: &mut Context<Self>,
 5113    ) -> Option<Task<Result<()>>> {
 5114        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5115
 5116        let actions_menu =
 5117            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5118                menu
 5119            } else {
 5120                return None;
 5121            };
 5122
 5123        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5124        let action = actions_menu.actions.get(action_ix)?;
 5125        let title = action.label();
 5126        let buffer = actions_menu.buffer;
 5127        let workspace = self.workspace()?;
 5128
 5129        match action {
 5130            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5131                match resolved_task.task_type() {
 5132                    task::TaskType::Script => workspace.update(cx, |workspace, cx| {
 5133                        workspace.schedule_resolved_task(
 5134                            task_source_kind,
 5135                            resolved_task,
 5136                            false,
 5137                            window,
 5138                            cx,
 5139                        );
 5140
 5141                        Some(Task::ready(Ok(())))
 5142                    }),
 5143                    task::TaskType::Debug(_) => {
 5144                        workspace.update(cx, |workspace, cx| {
 5145                            workspace.schedule_debug_task(resolved_task, window, cx);
 5146                        });
 5147                        Some(Task::ready(Ok(())))
 5148                    }
 5149                }
 5150            }
 5151            CodeActionsItem::CodeAction {
 5152                excerpt_id,
 5153                action,
 5154                provider,
 5155            } => {
 5156                let apply_code_action =
 5157                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5158                let workspace = workspace.downgrade();
 5159                Some(cx.spawn_in(window, async move |editor, cx| {
 5160                    let project_transaction = apply_code_action.await?;
 5161                    Self::open_project_transaction(
 5162                        &editor,
 5163                        workspace,
 5164                        project_transaction,
 5165                        title,
 5166                        cx,
 5167                    )
 5168                    .await
 5169                }))
 5170            }
 5171        }
 5172    }
 5173
 5174    pub async fn open_project_transaction(
 5175        this: &WeakEntity<Editor>,
 5176        workspace: WeakEntity<Workspace>,
 5177        transaction: ProjectTransaction,
 5178        title: String,
 5179        cx: &mut AsyncWindowContext,
 5180    ) -> Result<()> {
 5181        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5182        cx.update(|_, cx| {
 5183            entries.sort_unstable_by_key(|(buffer, _)| {
 5184                buffer.read(cx).file().map(|f| f.path().clone())
 5185            });
 5186        })?;
 5187
 5188        // If the project transaction's edits are all contained within this editor, then
 5189        // avoid opening a new editor to display them.
 5190
 5191        if let Some((buffer, transaction)) = entries.first() {
 5192            if entries.len() == 1 {
 5193                let excerpt = this.update(cx, |editor, cx| {
 5194                    editor
 5195                        .buffer()
 5196                        .read(cx)
 5197                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5198                })?;
 5199                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5200                    if excerpted_buffer == *buffer {
 5201                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5202                            let excerpt_range = excerpt_range.to_offset(buffer);
 5203                            buffer
 5204                                .edited_ranges_for_transaction::<usize>(transaction)
 5205                                .all(|range| {
 5206                                    excerpt_range.start <= range.start
 5207                                        && excerpt_range.end >= range.end
 5208                                })
 5209                        })?;
 5210
 5211                        if all_edits_within_excerpt {
 5212                            return Ok(());
 5213                        }
 5214                    }
 5215                }
 5216            }
 5217        } else {
 5218            return Ok(());
 5219        }
 5220
 5221        let mut ranges_to_highlight = Vec::new();
 5222        let excerpt_buffer = cx.new(|cx| {
 5223            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 5224            for (buffer_handle, transaction) in &entries {
 5225                let edited_ranges = buffer_handle
 5226                    .read(cx)
 5227                    .edited_ranges_for_transaction::<Point>(transaction)
 5228                    .collect::<Vec<_>>();
 5229                let (ranges, _) = multibuffer.set_excerpts_for_path(
 5230                    PathKey::for_buffer(buffer_handle, cx),
 5231                    buffer_handle.clone(),
 5232                    edited_ranges,
 5233                    DEFAULT_MULTIBUFFER_CONTEXT,
 5234                    cx,
 5235                );
 5236
 5237                ranges_to_highlight.extend(ranges);
 5238            }
 5239            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 5240            multibuffer
 5241        })?;
 5242
 5243        workspace.update_in(cx, |workspace, window, cx| {
 5244            let project = workspace.project().clone();
 5245            let editor =
 5246                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 5247            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 5248            editor.update(cx, |editor, cx| {
 5249                editor.highlight_background::<Self>(
 5250                    &ranges_to_highlight,
 5251                    |theme| theme.editor_highlighted_line_background,
 5252                    cx,
 5253                );
 5254            });
 5255        })?;
 5256
 5257        Ok(())
 5258    }
 5259
 5260    pub fn clear_code_action_providers(&mut self) {
 5261        self.code_action_providers.clear();
 5262        self.available_code_actions.take();
 5263    }
 5264
 5265    pub fn add_code_action_provider(
 5266        &mut self,
 5267        provider: Rc<dyn CodeActionProvider>,
 5268        window: &mut Window,
 5269        cx: &mut Context<Self>,
 5270    ) {
 5271        if self
 5272            .code_action_providers
 5273            .iter()
 5274            .any(|existing_provider| existing_provider.id() == provider.id())
 5275        {
 5276            return;
 5277        }
 5278
 5279        self.code_action_providers.push(provider);
 5280        self.refresh_code_actions(window, cx);
 5281    }
 5282
 5283    pub fn remove_code_action_provider(
 5284        &mut self,
 5285        id: Arc<str>,
 5286        window: &mut Window,
 5287        cx: &mut Context<Self>,
 5288    ) {
 5289        self.code_action_providers
 5290            .retain(|provider| provider.id() != id);
 5291        self.refresh_code_actions(window, cx);
 5292    }
 5293
 5294    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 5295        let newest_selection = self.selections.newest_anchor().clone();
 5296        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 5297        let buffer = self.buffer.read(cx);
 5298        if newest_selection.head().diff_base_anchor.is_some() {
 5299            return None;
 5300        }
 5301        let (start_buffer, start) =
 5302            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 5303        let (end_buffer, end) =
 5304            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 5305        if start_buffer != end_buffer {
 5306            return None;
 5307        }
 5308
 5309        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 5310            cx.background_executor()
 5311                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 5312                .await;
 5313
 5314            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 5315                let providers = this.code_action_providers.clone();
 5316                let tasks = this
 5317                    .code_action_providers
 5318                    .iter()
 5319                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 5320                    .collect::<Vec<_>>();
 5321                (providers, tasks)
 5322            })?;
 5323
 5324            let mut actions = Vec::new();
 5325            for (provider, provider_actions) in
 5326                providers.into_iter().zip(future::join_all(tasks).await)
 5327            {
 5328                if let Some(provider_actions) = provider_actions.log_err() {
 5329                    actions.extend(provider_actions.into_iter().map(|action| {
 5330                        AvailableCodeAction {
 5331                            excerpt_id: newest_selection.start.excerpt_id,
 5332                            action,
 5333                            provider: provider.clone(),
 5334                        }
 5335                    }));
 5336                }
 5337            }
 5338
 5339            this.update(cx, |this, cx| {
 5340                this.available_code_actions = if actions.is_empty() {
 5341                    None
 5342                } else {
 5343                    Some((
 5344                        Location {
 5345                            buffer: start_buffer,
 5346                            range: start..end,
 5347                        },
 5348                        actions.into(),
 5349                    ))
 5350                };
 5351                cx.notify();
 5352            })
 5353        }));
 5354        None
 5355    }
 5356
 5357    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5358        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 5359            self.show_git_blame_inline = false;
 5360
 5361            self.show_git_blame_inline_delay_task =
 5362                Some(cx.spawn_in(window, async move |this, cx| {
 5363                    cx.background_executor().timer(delay).await;
 5364
 5365                    this.update(cx, |this, cx| {
 5366                        this.show_git_blame_inline = true;
 5367                        cx.notify();
 5368                    })
 5369                    .log_err();
 5370                }));
 5371        }
 5372    }
 5373
 5374    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 5375        if self.pending_rename.is_some() {
 5376            return None;
 5377        }
 5378
 5379        let provider = self.semantics_provider.clone()?;
 5380        let buffer = self.buffer.read(cx);
 5381        let newest_selection = self.selections.newest_anchor().clone();
 5382        let cursor_position = newest_selection.head();
 5383        let (cursor_buffer, cursor_buffer_position) =
 5384            buffer.text_anchor_for_position(cursor_position, cx)?;
 5385        let (tail_buffer, _) = buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 5386        if cursor_buffer != tail_buffer {
 5387            return None;
 5388        }
 5389        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 5390        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 5391            cx.background_executor()
 5392                .timer(Duration::from_millis(debounce))
 5393                .await;
 5394
 5395            let highlights = if let Some(highlights) = cx
 5396                .update(|cx| {
 5397                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 5398                })
 5399                .ok()
 5400                .flatten()
 5401            {
 5402                highlights.await.log_err()
 5403            } else {
 5404                None
 5405            };
 5406
 5407            if let Some(highlights) = highlights {
 5408                this.update(cx, |this, cx| {
 5409                    if this.pending_rename.is_some() {
 5410                        return;
 5411                    }
 5412
 5413                    let buffer_id = cursor_position.buffer_id;
 5414                    let buffer = this.buffer.read(cx);
 5415                    if !buffer
 5416                        .text_anchor_for_position(cursor_position, cx)
 5417                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 5418                    {
 5419                        return;
 5420                    }
 5421
 5422                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 5423                    let mut write_ranges = Vec::new();
 5424                    let mut read_ranges = Vec::new();
 5425                    for highlight in highlights {
 5426                        for (excerpt_id, excerpt_range) in
 5427                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 5428                        {
 5429                            let start = highlight
 5430                                .range
 5431                                .start
 5432                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 5433                            let end = highlight
 5434                                .range
 5435                                .end
 5436                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 5437                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 5438                                continue;
 5439                            }
 5440
 5441                            let range = Anchor {
 5442                                buffer_id,
 5443                                excerpt_id,
 5444                                text_anchor: start,
 5445                                diff_base_anchor: None,
 5446                            }..Anchor {
 5447                                buffer_id,
 5448                                excerpt_id,
 5449                                text_anchor: end,
 5450                                diff_base_anchor: None,
 5451                            };
 5452                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 5453                                write_ranges.push(range);
 5454                            } else {
 5455                                read_ranges.push(range);
 5456                            }
 5457                        }
 5458                    }
 5459
 5460                    this.highlight_background::<DocumentHighlightRead>(
 5461                        &read_ranges,
 5462                        |theme| theme.editor_document_highlight_read_background,
 5463                        cx,
 5464                    );
 5465                    this.highlight_background::<DocumentHighlightWrite>(
 5466                        &write_ranges,
 5467                        |theme| theme.editor_document_highlight_write_background,
 5468                        cx,
 5469                    );
 5470                    cx.notify();
 5471                })
 5472                .log_err();
 5473            }
 5474        }));
 5475        None
 5476    }
 5477
 5478    fn prepare_highlight_query_from_selection(
 5479        &mut self,
 5480        cx: &mut Context<Editor>,
 5481    ) -> Option<(String, Range<Anchor>)> {
 5482        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 5483            return None;
 5484        }
 5485        if !EditorSettings::get_global(cx).selection_highlight {
 5486            return None;
 5487        }
 5488        if self.selections.count() != 1 || self.selections.line_mode {
 5489            return None;
 5490        }
 5491        let selection = self.selections.newest::<Point>(cx);
 5492        if selection.is_empty() || selection.start.row != selection.end.row {
 5493            return None;
 5494        }
 5495        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 5496        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 5497        let query = multi_buffer_snapshot
 5498            .text_for_range(selection_anchor_range.clone())
 5499            .collect::<String>();
 5500        if query.trim().is_empty() {
 5501            return None;
 5502        }
 5503        Some((query, selection_anchor_range))
 5504    }
 5505
 5506    fn update_selection_occurrence_highlights(
 5507        &mut self,
 5508        query_text: String,
 5509        query_range: Range<Anchor>,
 5510        multi_buffer_range_to_query: Range<Point>,
 5511        use_debounce: bool,
 5512        window: &mut Window,
 5513        cx: &mut Context<Editor>,
 5514    ) -> Task<()> {
 5515        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 5516        cx.spawn_in(window, async move |editor, cx| {
 5517            if use_debounce {
 5518                cx.background_executor()
 5519                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 5520                    .await;
 5521            }
 5522            let match_task = cx.background_spawn(async move {
 5523                let buffer_ranges = multi_buffer_snapshot
 5524                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 5525                    .into_iter()
 5526                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 5527                let mut match_ranges = Vec::new();
 5528                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 5529                    match_ranges.extend(
 5530                        project::search::SearchQuery::text(
 5531                            query_text.clone(),
 5532                            false,
 5533                            false,
 5534                            false,
 5535                            Default::default(),
 5536                            Default::default(),
 5537                            false,
 5538                            None,
 5539                        )
 5540                        .unwrap()
 5541                        .search(&buffer_snapshot, Some(search_range.clone()))
 5542                        .await
 5543                        .into_iter()
 5544                        .filter_map(|match_range| {
 5545                            let match_start = buffer_snapshot
 5546                                .anchor_after(search_range.start + match_range.start);
 5547                            let match_end =
 5548                                buffer_snapshot.anchor_before(search_range.start + match_range.end);
 5549                            let match_anchor_range = Anchor::range_in_buffer(
 5550                                excerpt_id,
 5551                                buffer_snapshot.remote_id(),
 5552                                match_start..match_end,
 5553                            );
 5554                            (match_anchor_range != query_range).then_some(match_anchor_range)
 5555                        }),
 5556                    );
 5557                }
 5558                match_ranges
 5559            });
 5560            let match_ranges = match_task.await;
 5561            editor
 5562                .update_in(cx, |editor, _, cx| {
 5563                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 5564                    if !match_ranges.is_empty() {
 5565                        editor.highlight_background::<SelectedTextHighlight>(
 5566                            &match_ranges,
 5567                            |theme| theme.editor_document_highlight_bracket_background,
 5568                            cx,
 5569                        )
 5570                    }
 5571                })
 5572                .log_err();
 5573        })
 5574    }
 5575
 5576    fn refresh_selected_text_highlights(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 5577        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 5578        else {
 5579            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 5580            self.quick_selection_highlight_task.take();
 5581            self.debounced_selection_highlight_task.take();
 5582            return;
 5583        };
 5584        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 5585        if self
 5586            .quick_selection_highlight_task
 5587            .as_ref()
 5588            .map_or(true, |(prev_anchor_range, _)| {
 5589                prev_anchor_range != &query_range
 5590            })
 5591        {
 5592            let multi_buffer_visible_start = self
 5593                .scroll_manager
 5594                .anchor()
 5595                .anchor
 5596                .to_point(&multi_buffer_snapshot);
 5597            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5598                multi_buffer_visible_start
 5599                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5600                Bias::Left,
 5601            );
 5602            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5603            self.quick_selection_highlight_task = Some((
 5604                query_range.clone(),
 5605                self.update_selection_occurrence_highlights(
 5606                    query_text.clone(),
 5607                    query_range.clone(),
 5608                    multi_buffer_visible_range,
 5609                    false,
 5610                    window,
 5611                    cx,
 5612                ),
 5613            ));
 5614        }
 5615        if self
 5616            .debounced_selection_highlight_task
 5617            .as_ref()
 5618            .map_or(true, |(prev_anchor_range, _)| {
 5619                prev_anchor_range != &query_range
 5620            })
 5621        {
 5622            let multi_buffer_start = multi_buffer_snapshot
 5623                .anchor_before(0)
 5624                .to_point(&multi_buffer_snapshot);
 5625            let multi_buffer_end = multi_buffer_snapshot
 5626                .anchor_after(multi_buffer_snapshot.len())
 5627                .to_point(&multi_buffer_snapshot);
 5628            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 5629            self.debounced_selection_highlight_task = Some((
 5630                query_range.clone(),
 5631                self.update_selection_occurrence_highlights(
 5632                    query_text,
 5633                    query_range,
 5634                    multi_buffer_full_range,
 5635                    true,
 5636                    window,
 5637                    cx,
 5638                ),
 5639            ));
 5640        }
 5641    }
 5642
 5643    pub fn refresh_inline_completion(
 5644        &mut self,
 5645        debounce: bool,
 5646        user_requested: bool,
 5647        window: &mut Window,
 5648        cx: &mut Context<Self>,
 5649    ) -> Option<()> {
 5650        let provider = self.edit_prediction_provider()?;
 5651        let cursor = self.selections.newest_anchor().head();
 5652        let (buffer, cursor_buffer_position) =
 5653            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 5654
 5655        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 5656            self.discard_inline_completion(false, cx);
 5657            return None;
 5658        }
 5659
 5660        if !user_requested
 5661            && (!self.should_show_edit_predictions()
 5662                || !self.is_focused(window)
 5663                || buffer.read(cx).is_empty())
 5664        {
 5665            self.discard_inline_completion(false, cx);
 5666            return None;
 5667        }
 5668
 5669        self.update_visible_inline_completion(window, cx);
 5670        provider.refresh(
 5671            self.project.clone(),
 5672            buffer,
 5673            cursor_buffer_position,
 5674            debounce,
 5675            cx,
 5676        );
 5677        Some(())
 5678    }
 5679
 5680    fn show_edit_predictions_in_menu(&self) -> bool {
 5681        match self.edit_prediction_settings {
 5682            EditPredictionSettings::Disabled => false,
 5683            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 5684        }
 5685    }
 5686
 5687    pub fn edit_predictions_enabled(&self) -> bool {
 5688        match self.edit_prediction_settings {
 5689            EditPredictionSettings::Disabled => false,
 5690            EditPredictionSettings::Enabled { .. } => true,
 5691        }
 5692    }
 5693
 5694    fn edit_prediction_requires_modifier(&self) -> bool {
 5695        match self.edit_prediction_settings {
 5696            EditPredictionSettings::Disabled => false,
 5697            EditPredictionSettings::Enabled {
 5698                preview_requires_modifier,
 5699                ..
 5700            } => preview_requires_modifier,
 5701        }
 5702    }
 5703
 5704    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 5705        if self.edit_prediction_provider.is_none() {
 5706            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 5707        } else {
 5708            let selection = self.selections.newest_anchor();
 5709            let cursor = selection.head();
 5710
 5711            if let Some((buffer, cursor_buffer_position)) =
 5712                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 5713            {
 5714                self.edit_prediction_settings =
 5715                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 5716            }
 5717        }
 5718    }
 5719
 5720    fn edit_prediction_settings_at_position(
 5721        &self,
 5722        buffer: &Entity<Buffer>,
 5723        buffer_position: language::Anchor,
 5724        cx: &App,
 5725    ) -> EditPredictionSettings {
 5726        if !self.mode.is_full()
 5727            || !self.show_inline_completions_override.unwrap_or(true)
 5728            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 5729        {
 5730            return EditPredictionSettings::Disabled;
 5731        }
 5732
 5733        let buffer = buffer.read(cx);
 5734
 5735        let file = buffer.file();
 5736
 5737        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 5738            return EditPredictionSettings::Disabled;
 5739        };
 5740
 5741        let by_provider = matches!(
 5742            self.menu_inline_completions_policy,
 5743            MenuInlineCompletionsPolicy::ByProvider
 5744        );
 5745
 5746        let show_in_menu = by_provider
 5747            && self
 5748                .edit_prediction_provider
 5749                .as_ref()
 5750                .map_or(false, |provider| {
 5751                    provider.provider.show_completions_in_menu()
 5752                });
 5753
 5754        let preview_requires_modifier =
 5755            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 5756
 5757        EditPredictionSettings::Enabled {
 5758            show_in_menu,
 5759            preview_requires_modifier,
 5760        }
 5761    }
 5762
 5763    fn should_show_edit_predictions(&self) -> bool {
 5764        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 5765    }
 5766
 5767    pub fn edit_prediction_preview_is_active(&self) -> bool {
 5768        matches!(
 5769            self.edit_prediction_preview,
 5770            EditPredictionPreview::Active { .. }
 5771        )
 5772    }
 5773
 5774    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 5775        let cursor = self.selections.newest_anchor().head();
 5776        if let Some((buffer, cursor_position)) =
 5777            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 5778        {
 5779            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 5780        } else {
 5781            false
 5782        }
 5783    }
 5784
 5785    fn edit_predictions_enabled_in_buffer(
 5786        &self,
 5787        buffer: &Entity<Buffer>,
 5788        buffer_position: language::Anchor,
 5789        cx: &App,
 5790    ) -> bool {
 5791        maybe!({
 5792            if self.read_only(cx) {
 5793                return Some(false);
 5794            }
 5795            let provider = self.edit_prediction_provider()?;
 5796            if !provider.is_enabled(&buffer, buffer_position, cx) {
 5797                return Some(false);
 5798            }
 5799            let buffer = buffer.read(cx);
 5800            let Some(file) = buffer.file() else {
 5801                return Some(true);
 5802            };
 5803            let settings = all_language_settings(Some(file), cx);
 5804            Some(settings.edit_predictions_enabled_for_file(file, cx))
 5805        })
 5806        .unwrap_or(false)
 5807    }
 5808
 5809    fn cycle_inline_completion(
 5810        &mut self,
 5811        direction: Direction,
 5812        window: &mut Window,
 5813        cx: &mut Context<Self>,
 5814    ) -> Option<()> {
 5815        let provider = self.edit_prediction_provider()?;
 5816        let cursor = self.selections.newest_anchor().head();
 5817        let (buffer, cursor_buffer_position) =
 5818            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 5819        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 5820            return None;
 5821        }
 5822
 5823        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 5824        self.update_visible_inline_completion(window, cx);
 5825
 5826        Some(())
 5827    }
 5828
 5829    pub fn show_inline_completion(
 5830        &mut self,
 5831        _: &ShowEditPrediction,
 5832        window: &mut Window,
 5833        cx: &mut Context<Self>,
 5834    ) {
 5835        if !self.has_active_inline_completion() {
 5836            self.refresh_inline_completion(false, true, window, cx);
 5837            return;
 5838        }
 5839
 5840        self.update_visible_inline_completion(window, cx);
 5841    }
 5842
 5843    pub fn display_cursor_names(
 5844        &mut self,
 5845        _: &DisplayCursorNames,
 5846        window: &mut Window,
 5847        cx: &mut Context<Self>,
 5848    ) {
 5849        self.show_cursor_names(window, cx);
 5850    }
 5851
 5852    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5853        self.show_cursor_names = true;
 5854        cx.notify();
 5855        cx.spawn_in(window, async move |this, cx| {
 5856            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 5857            this.update(cx, |this, cx| {
 5858                this.show_cursor_names = false;
 5859                cx.notify()
 5860            })
 5861            .ok()
 5862        })
 5863        .detach();
 5864    }
 5865
 5866    pub fn next_edit_prediction(
 5867        &mut self,
 5868        _: &NextEditPrediction,
 5869        window: &mut Window,
 5870        cx: &mut Context<Self>,
 5871    ) {
 5872        if self.has_active_inline_completion() {
 5873            self.cycle_inline_completion(Direction::Next, window, cx);
 5874        } else {
 5875            let is_copilot_disabled = self
 5876                .refresh_inline_completion(false, true, window, cx)
 5877                .is_none();
 5878            if is_copilot_disabled {
 5879                cx.propagate();
 5880            }
 5881        }
 5882    }
 5883
 5884    pub fn previous_edit_prediction(
 5885        &mut self,
 5886        _: &PreviousEditPrediction,
 5887        window: &mut Window,
 5888        cx: &mut Context<Self>,
 5889    ) {
 5890        if self.has_active_inline_completion() {
 5891            self.cycle_inline_completion(Direction::Prev, window, cx);
 5892        } else {
 5893            let is_copilot_disabled = self
 5894                .refresh_inline_completion(false, true, window, cx)
 5895                .is_none();
 5896            if is_copilot_disabled {
 5897                cx.propagate();
 5898            }
 5899        }
 5900    }
 5901
 5902    pub fn accept_edit_prediction(
 5903        &mut self,
 5904        _: &AcceptEditPrediction,
 5905        window: &mut Window,
 5906        cx: &mut Context<Self>,
 5907    ) {
 5908        if self.show_edit_predictions_in_menu() {
 5909            self.hide_context_menu(window, cx);
 5910        }
 5911
 5912        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 5913            return;
 5914        };
 5915
 5916        self.report_inline_completion_event(
 5917            active_inline_completion.completion_id.clone(),
 5918            true,
 5919            cx,
 5920        );
 5921
 5922        match &active_inline_completion.completion {
 5923            InlineCompletion::Move { target, .. } => {
 5924                let target = *target;
 5925
 5926                if let Some(position_map) = &self.last_position_map {
 5927                    if position_map
 5928                        .visible_row_range
 5929                        .contains(&target.to_display_point(&position_map.snapshot).row())
 5930                        || !self.edit_prediction_requires_modifier()
 5931                    {
 5932                        self.unfold_ranges(&[target..target], true, false, cx);
 5933                        // Note that this is also done in vim's handler of the Tab action.
 5934                        self.change_selections(
 5935                            Some(Autoscroll::newest()),
 5936                            window,
 5937                            cx,
 5938                            |selections| {
 5939                                selections.select_anchor_ranges([target..target]);
 5940                            },
 5941                        );
 5942                        self.clear_row_highlights::<EditPredictionPreview>();
 5943
 5944                        self.edit_prediction_preview
 5945                            .set_previous_scroll_position(None);
 5946                    } else {
 5947                        self.edit_prediction_preview
 5948                            .set_previous_scroll_position(Some(
 5949                                position_map.snapshot.scroll_anchor,
 5950                            ));
 5951
 5952                        self.highlight_rows::<EditPredictionPreview>(
 5953                            target..target,
 5954                            cx.theme().colors().editor_highlighted_line_background,
 5955                            true,
 5956                            cx,
 5957                        );
 5958                        self.request_autoscroll(Autoscroll::fit(), cx);
 5959                    }
 5960                }
 5961            }
 5962            InlineCompletion::Edit { edits, .. } => {
 5963                if let Some(provider) = self.edit_prediction_provider() {
 5964                    provider.accept(cx);
 5965                }
 5966
 5967                let snapshot = self.buffer.read(cx).snapshot(cx);
 5968                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 5969
 5970                self.buffer.update(cx, |buffer, cx| {
 5971                    buffer.edit(edits.iter().cloned(), None, cx)
 5972                });
 5973
 5974                self.change_selections(None, window, cx, |s| {
 5975                    s.select_anchor_ranges([last_edit_end..last_edit_end])
 5976                });
 5977
 5978                self.update_visible_inline_completion(window, cx);
 5979                if self.active_inline_completion.is_none() {
 5980                    self.refresh_inline_completion(true, true, window, cx);
 5981                }
 5982
 5983                cx.notify();
 5984            }
 5985        }
 5986
 5987        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 5988    }
 5989
 5990    pub fn accept_partial_inline_completion(
 5991        &mut self,
 5992        _: &AcceptPartialEditPrediction,
 5993        window: &mut Window,
 5994        cx: &mut Context<Self>,
 5995    ) {
 5996        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 5997            return;
 5998        };
 5999        if self.selections.count() != 1 {
 6000            return;
 6001        }
 6002
 6003        self.report_inline_completion_event(
 6004            active_inline_completion.completion_id.clone(),
 6005            true,
 6006            cx,
 6007        );
 6008
 6009        match &active_inline_completion.completion {
 6010            InlineCompletion::Move { target, .. } => {
 6011                let target = *target;
 6012                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6013                    selections.select_anchor_ranges([target..target]);
 6014                });
 6015            }
 6016            InlineCompletion::Edit { edits, .. } => {
 6017                // Find an insertion that starts at the cursor position.
 6018                let snapshot = self.buffer.read(cx).snapshot(cx);
 6019                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6020                let insertion = edits.iter().find_map(|(range, text)| {
 6021                    let range = range.to_offset(&snapshot);
 6022                    if range.is_empty() && range.start == cursor_offset {
 6023                        Some(text)
 6024                    } else {
 6025                        None
 6026                    }
 6027                });
 6028
 6029                if let Some(text) = insertion {
 6030                    let mut partial_completion = text
 6031                        .chars()
 6032                        .by_ref()
 6033                        .take_while(|c| c.is_alphabetic())
 6034                        .collect::<String>();
 6035                    if partial_completion.is_empty() {
 6036                        partial_completion = text
 6037                            .chars()
 6038                            .by_ref()
 6039                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 6040                            .collect::<String>();
 6041                    }
 6042
 6043                    cx.emit(EditorEvent::InputHandled {
 6044                        utf16_range_to_replace: None,
 6045                        text: partial_completion.clone().into(),
 6046                    });
 6047
 6048                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 6049
 6050                    self.refresh_inline_completion(true, true, window, cx);
 6051                    cx.notify();
 6052                } else {
 6053                    self.accept_edit_prediction(&Default::default(), window, cx);
 6054                }
 6055            }
 6056        }
 6057    }
 6058
 6059    fn discard_inline_completion(
 6060        &mut self,
 6061        should_report_inline_completion_event: bool,
 6062        cx: &mut Context<Self>,
 6063    ) -> bool {
 6064        if should_report_inline_completion_event {
 6065            let completion_id = self
 6066                .active_inline_completion
 6067                .as_ref()
 6068                .and_then(|active_completion| active_completion.completion_id.clone());
 6069
 6070            self.report_inline_completion_event(completion_id, false, cx);
 6071        }
 6072
 6073        if let Some(provider) = self.edit_prediction_provider() {
 6074            provider.discard(cx);
 6075        }
 6076
 6077        self.take_active_inline_completion(cx)
 6078    }
 6079
 6080    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 6081        let Some(provider) = self.edit_prediction_provider() else {
 6082            return;
 6083        };
 6084
 6085        let Some((_, buffer, _)) = self
 6086            .buffer
 6087            .read(cx)
 6088            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 6089        else {
 6090            return;
 6091        };
 6092
 6093        let extension = buffer
 6094            .read(cx)
 6095            .file()
 6096            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 6097
 6098        let event_type = match accepted {
 6099            true => "Edit Prediction Accepted",
 6100            false => "Edit Prediction Discarded",
 6101        };
 6102        telemetry::event!(
 6103            event_type,
 6104            provider = provider.name(),
 6105            prediction_id = id,
 6106            suggestion_accepted = accepted,
 6107            file_extension = extension,
 6108        );
 6109    }
 6110
 6111    pub fn has_active_inline_completion(&self) -> bool {
 6112        self.active_inline_completion.is_some()
 6113    }
 6114
 6115    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 6116        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 6117            return false;
 6118        };
 6119
 6120        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 6121        self.clear_highlights::<InlineCompletionHighlight>(cx);
 6122        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 6123        true
 6124    }
 6125
 6126    /// Returns true when we're displaying the edit prediction popover below the cursor
 6127    /// like we are not previewing and the LSP autocomplete menu is visible
 6128    /// or we are in `when_holding_modifier` mode.
 6129    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 6130        if self.edit_prediction_preview_is_active()
 6131            || !self.show_edit_predictions_in_menu()
 6132            || !self.edit_predictions_enabled()
 6133        {
 6134            return false;
 6135        }
 6136
 6137        if self.has_visible_completions_menu() {
 6138            return true;
 6139        }
 6140
 6141        has_completion && self.edit_prediction_requires_modifier()
 6142    }
 6143
 6144    fn handle_modifiers_changed(
 6145        &mut self,
 6146        modifiers: Modifiers,
 6147        position_map: &PositionMap,
 6148        window: &mut Window,
 6149        cx: &mut Context<Self>,
 6150    ) {
 6151        if self.show_edit_predictions_in_menu() {
 6152            self.update_edit_prediction_preview(&modifiers, window, cx);
 6153        }
 6154
 6155        self.update_selection_mode(&modifiers, position_map, window, cx);
 6156
 6157        let mouse_position = window.mouse_position();
 6158        if !position_map.text_hitbox.is_hovered(window) {
 6159            return;
 6160        }
 6161
 6162        self.update_hovered_link(
 6163            position_map.point_for_position(mouse_position),
 6164            &position_map.snapshot,
 6165            modifiers,
 6166            window,
 6167            cx,
 6168        )
 6169    }
 6170
 6171    fn update_selection_mode(
 6172        &mut self,
 6173        modifiers: &Modifiers,
 6174        position_map: &PositionMap,
 6175        window: &mut Window,
 6176        cx: &mut Context<Self>,
 6177    ) {
 6178        if modifiers != &COLUMNAR_SELECTION_MODIFIERS || self.selections.pending.is_none() {
 6179            return;
 6180        }
 6181
 6182        let mouse_position = window.mouse_position();
 6183        let point_for_position = position_map.point_for_position(mouse_position);
 6184        let position = point_for_position.previous_valid;
 6185
 6186        self.select(
 6187            SelectPhase::BeginColumnar {
 6188                position,
 6189                reset: false,
 6190                goal_column: point_for_position.exact_unclipped.column(),
 6191            },
 6192            window,
 6193            cx,
 6194        );
 6195    }
 6196
 6197    fn update_edit_prediction_preview(
 6198        &mut self,
 6199        modifiers: &Modifiers,
 6200        window: &mut Window,
 6201        cx: &mut Context<Self>,
 6202    ) {
 6203        let accept_keybind = self.accept_edit_prediction_keybind(window, cx);
 6204        let Some(accept_keystroke) = accept_keybind.keystroke() else {
 6205            return;
 6206        };
 6207
 6208        if &accept_keystroke.modifiers == modifiers && accept_keystroke.modifiers.modified() {
 6209            if matches!(
 6210                self.edit_prediction_preview,
 6211                EditPredictionPreview::Inactive { .. }
 6212            ) {
 6213                self.edit_prediction_preview = EditPredictionPreview::Active {
 6214                    previous_scroll_position: None,
 6215                    since: Instant::now(),
 6216                };
 6217
 6218                self.update_visible_inline_completion(window, cx);
 6219                cx.notify();
 6220            }
 6221        } else if let EditPredictionPreview::Active {
 6222            previous_scroll_position,
 6223            since,
 6224        } = self.edit_prediction_preview
 6225        {
 6226            if let (Some(previous_scroll_position), Some(position_map)) =
 6227                (previous_scroll_position, self.last_position_map.as_ref())
 6228            {
 6229                self.set_scroll_position(
 6230                    previous_scroll_position
 6231                        .scroll_position(&position_map.snapshot.display_snapshot),
 6232                    window,
 6233                    cx,
 6234                );
 6235            }
 6236
 6237            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 6238                released_too_fast: since.elapsed() < Duration::from_millis(200),
 6239            };
 6240            self.clear_row_highlights::<EditPredictionPreview>();
 6241            self.update_visible_inline_completion(window, cx);
 6242            cx.notify();
 6243        }
 6244    }
 6245
 6246    fn update_visible_inline_completion(
 6247        &mut self,
 6248        _window: &mut Window,
 6249        cx: &mut Context<Self>,
 6250    ) -> Option<()> {
 6251        let selection = self.selections.newest_anchor();
 6252        let cursor = selection.head();
 6253        let multibuffer = self.buffer.read(cx).snapshot(cx);
 6254        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 6255        let excerpt_id = cursor.excerpt_id;
 6256
 6257        let show_in_menu = self.show_edit_predictions_in_menu();
 6258        let completions_menu_has_precedence = !show_in_menu
 6259            && (self.context_menu.borrow().is_some()
 6260                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 6261
 6262        if completions_menu_has_precedence
 6263            || !offset_selection.is_empty()
 6264            || self
 6265                .active_inline_completion
 6266                .as_ref()
 6267                .map_or(false, |completion| {
 6268                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 6269                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 6270                    !invalidation_range.contains(&offset_selection.head())
 6271                })
 6272        {
 6273            self.discard_inline_completion(false, cx);
 6274            return None;
 6275        }
 6276
 6277        self.take_active_inline_completion(cx);
 6278        let Some(provider) = self.edit_prediction_provider() else {
 6279            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6280            return None;
 6281        };
 6282
 6283        let (buffer, cursor_buffer_position) =
 6284            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6285
 6286        self.edit_prediction_settings =
 6287            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6288
 6289        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 6290
 6291        if self.edit_prediction_indent_conflict {
 6292            let cursor_point = cursor.to_point(&multibuffer);
 6293
 6294            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 6295
 6296            if let Some((_, indent)) = indents.iter().next() {
 6297                if indent.len == cursor_point.column {
 6298                    self.edit_prediction_indent_conflict = false;
 6299                }
 6300            }
 6301        }
 6302
 6303        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 6304        let edits = inline_completion
 6305            .edits
 6306            .into_iter()
 6307            .flat_map(|(range, new_text)| {
 6308                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 6309                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 6310                Some((start..end, new_text))
 6311            })
 6312            .collect::<Vec<_>>();
 6313        if edits.is_empty() {
 6314            return None;
 6315        }
 6316
 6317        let first_edit_start = edits.first().unwrap().0.start;
 6318        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 6319        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 6320
 6321        let last_edit_end = edits.last().unwrap().0.end;
 6322        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 6323        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 6324
 6325        let cursor_row = cursor.to_point(&multibuffer).row;
 6326
 6327        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 6328
 6329        let mut inlay_ids = Vec::new();
 6330        let invalidation_row_range;
 6331        let move_invalidation_row_range = if cursor_row < edit_start_row {
 6332            Some(cursor_row..edit_end_row)
 6333        } else if cursor_row > edit_end_row {
 6334            Some(edit_start_row..cursor_row)
 6335        } else {
 6336            None
 6337        };
 6338        let is_move =
 6339            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 6340        let completion = if is_move {
 6341            invalidation_row_range =
 6342                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 6343            let target = first_edit_start;
 6344            InlineCompletion::Move { target, snapshot }
 6345        } else {
 6346            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 6347                && !self.inline_completions_hidden_for_vim_mode;
 6348
 6349            if show_completions_in_buffer {
 6350                if edits
 6351                    .iter()
 6352                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 6353                {
 6354                    let mut inlays = Vec::new();
 6355                    for (range, new_text) in &edits {
 6356                        let inlay = Inlay::inline_completion(
 6357                            post_inc(&mut self.next_inlay_id),
 6358                            range.start,
 6359                            new_text.as_str(),
 6360                        );
 6361                        inlay_ids.push(inlay.id);
 6362                        inlays.push(inlay);
 6363                    }
 6364
 6365                    self.splice_inlays(&[], inlays, cx);
 6366                } else {
 6367                    let background_color = cx.theme().status().deleted_background;
 6368                    self.highlight_text::<InlineCompletionHighlight>(
 6369                        edits.iter().map(|(range, _)| range.clone()).collect(),
 6370                        HighlightStyle {
 6371                            background_color: Some(background_color),
 6372                            ..Default::default()
 6373                        },
 6374                        cx,
 6375                    );
 6376                }
 6377            }
 6378
 6379            invalidation_row_range = edit_start_row..edit_end_row;
 6380
 6381            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 6382                if provider.show_tab_accept_marker() {
 6383                    EditDisplayMode::TabAccept
 6384                } else {
 6385                    EditDisplayMode::Inline
 6386                }
 6387            } else {
 6388                EditDisplayMode::DiffPopover
 6389            };
 6390
 6391            InlineCompletion::Edit {
 6392                edits,
 6393                edit_preview: inline_completion.edit_preview,
 6394                display_mode,
 6395                snapshot,
 6396            }
 6397        };
 6398
 6399        let invalidation_range = multibuffer
 6400            .anchor_before(Point::new(invalidation_row_range.start, 0))
 6401            ..multibuffer.anchor_after(Point::new(
 6402                invalidation_row_range.end,
 6403                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 6404            ));
 6405
 6406        self.stale_inline_completion_in_menu = None;
 6407        self.active_inline_completion = Some(InlineCompletionState {
 6408            inlay_ids,
 6409            completion,
 6410            completion_id: inline_completion.id,
 6411            invalidation_range,
 6412        });
 6413
 6414        cx.notify();
 6415
 6416        Some(())
 6417    }
 6418
 6419    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 6420        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 6421    }
 6422
 6423    fn render_code_actions_indicator(
 6424        &self,
 6425        _style: &EditorStyle,
 6426        row: DisplayRow,
 6427        is_active: bool,
 6428        breakpoint: Option<&(Anchor, Breakpoint)>,
 6429        cx: &mut Context<Self>,
 6430    ) -> Option<IconButton> {
 6431        let color = Color::Muted;
 6432        let position = breakpoint.as_ref().map(|(anchor, _)| *anchor);
 6433        let show_tooltip = !self.context_menu_visible();
 6434
 6435        if self.available_code_actions.is_some() {
 6436            Some(
 6437                IconButton::new("code_actions_indicator", ui::IconName::Bolt)
 6438                    .shape(ui::IconButtonShape::Square)
 6439                    .icon_size(IconSize::XSmall)
 6440                    .icon_color(color)
 6441                    .toggle_state(is_active)
 6442                    .when(show_tooltip, |this| {
 6443                        this.tooltip({
 6444                            let focus_handle = self.focus_handle.clone();
 6445                            move |window, cx| {
 6446                                Tooltip::for_action_in(
 6447                                    "Toggle Code Actions",
 6448                                    &ToggleCodeActions {
 6449                                        deployed_from_indicator: None,
 6450                                    },
 6451                                    &focus_handle,
 6452                                    window,
 6453                                    cx,
 6454                                )
 6455                            }
 6456                        })
 6457                    })
 6458                    .on_click(cx.listener(move |editor, _e, window, cx| {
 6459                        window.focus(&editor.focus_handle(cx));
 6460                        editor.toggle_code_actions(
 6461                            &ToggleCodeActions {
 6462                                deployed_from_indicator: Some(row),
 6463                            },
 6464                            window,
 6465                            cx,
 6466                        );
 6467                    }))
 6468                    .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 6469                        editor.set_breakpoint_context_menu(
 6470                            row,
 6471                            position,
 6472                            event.down.position,
 6473                            window,
 6474                            cx,
 6475                        );
 6476                    })),
 6477            )
 6478        } else {
 6479            None
 6480        }
 6481    }
 6482
 6483    fn clear_tasks(&mut self) {
 6484        self.tasks.clear()
 6485    }
 6486
 6487    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 6488        if self.tasks.insert(key, value).is_some() {
 6489            // This case should hopefully be rare, but just in case...
 6490            log::error!(
 6491                "multiple different run targets found on a single line, only the last target will be rendered"
 6492            )
 6493        }
 6494    }
 6495
 6496    /// Get all display points of breakpoints that will be rendered within editor
 6497    ///
 6498    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 6499    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 6500    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 6501    fn active_breakpoints(
 6502        &self,
 6503        range: Range<DisplayRow>,
 6504        window: &mut Window,
 6505        cx: &mut Context<Self>,
 6506    ) -> HashMap<DisplayRow, (Anchor, Breakpoint)> {
 6507        let mut breakpoint_display_points = HashMap::default();
 6508
 6509        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 6510            return breakpoint_display_points;
 6511        };
 6512
 6513        let snapshot = self.snapshot(window, cx);
 6514
 6515        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 6516        let Some(project) = self.project.as_ref() else {
 6517            return breakpoint_display_points;
 6518        };
 6519
 6520        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 6521            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 6522
 6523        for (buffer_snapshot, range, excerpt_id) in
 6524            multi_buffer_snapshot.range_to_buffer_ranges(range)
 6525        {
 6526            let Some(buffer) = project.read_with(cx, |this, cx| {
 6527                this.buffer_for_id(buffer_snapshot.remote_id(), cx)
 6528            }) else {
 6529                continue;
 6530            };
 6531            let breakpoints = breakpoint_store.read(cx).breakpoints(
 6532                &buffer,
 6533                Some(
 6534                    buffer_snapshot.anchor_before(range.start)
 6535                        ..buffer_snapshot.anchor_after(range.end),
 6536                ),
 6537                buffer_snapshot,
 6538                cx,
 6539            );
 6540            for (anchor, breakpoint) in breakpoints {
 6541                let multi_buffer_anchor =
 6542                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), *anchor);
 6543                let position = multi_buffer_anchor
 6544                    .to_point(&multi_buffer_snapshot)
 6545                    .to_display_point(&snapshot);
 6546
 6547                breakpoint_display_points
 6548                    .insert(position.row(), (multi_buffer_anchor, breakpoint.clone()));
 6549            }
 6550        }
 6551
 6552        breakpoint_display_points
 6553    }
 6554
 6555    fn breakpoint_context_menu(
 6556        &self,
 6557        anchor: Anchor,
 6558        window: &mut Window,
 6559        cx: &mut Context<Self>,
 6560    ) -> Entity<ui::ContextMenu> {
 6561        let weak_editor = cx.weak_entity();
 6562        let focus_handle = self.focus_handle(cx);
 6563
 6564        let row = self
 6565            .buffer
 6566            .read(cx)
 6567            .snapshot(cx)
 6568            .summary_for_anchor::<Point>(&anchor)
 6569            .row;
 6570
 6571        let breakpoint = self
 6572            .breakpoint_at_row(row, window, cx)
 6573            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 6574
 6575        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 6576            "Edit Log Breakpoint"
 6577        } else {
 6578            "Set Log Breakpoint"
 6579        };
 6580
 6581        let condition_breakpoint_msg = if breakpoint
 6582            .as_ref()
 6583            .is_some_and(|bp| bp.1.condition.is_some())
 6584        {
 6585            "Edit Condition Breakpoint"
 6586        } else {
 6587            "Set Condition Breakpoint"
 6588        };
 6589
 6590        let hit_condition_breakpoint_msg = if breakpoint
 6591            .as_ref()
 6592            .is_some_and(|bp| bp.1.hit_condition.is_some())
 6593        {
 6594            "Edit Hit Condition Breakpoint"
 6595        } else {
 6596            "Set Hit Condition Breakpoint"
 6597        };
 6598
 6599        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 6600            "Unset Breakpoint"
 6601        } else {
 6602            "Set Breakpoint"
 6603        };
 6604
 6605        let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx)
 6606            .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor));
 6607
 6608        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 6609            BreakpointState::Enabled => Some("Disable"),
 6610            BreakpointState::Disabled => Some("Enable"),
 6611        });
 6612
 6613        let (anchor, breakpoint) =
 6614            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 6615
 6616        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 6617            menu.on_blur_subscription(Subscription::new(|| {}))
 6618                .context(focus_handle)
 6619                .when(run_to_cursor, |this| {
 6620                    let weak_editor = weak_editor.clone();
 6621                    this.entry("Run to cursor", None, move |window, cx| {
 6622                        weak_editor
 6623                            .update(cx, |editor, cx| {
 6624                                editor.change_selections(None, window, cx, |s| {
 6625                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 6626                                });
 6627                            })
 6628                            .ok();
 6629
 6630                        window.dispatch_action(Box::new(DebuggerRunToCursor), cx);
 6631                    })
 6632                    .separator()
 6633                })
 6634                .when_some(toggle_state_msg, |this, msg| {
 6635                    this.entry(msg, None, {
 6636                        let weak_editor = weak_editor.clone();
 6637                        let breakpoint = breakpoint.clone();
 6638                        move |_window, cx| {
 6639                            weak_editor
 6640                                .update(cx, |this, cx| {
 6641                                    this.edit_breakpoint_at_anchor(
 6642                                        anchor,
 6643                                        breakpoint.as_ref().clone(),
 6644                                        BreakpointEditAction::InvertState,
 6645                                        cx,
 6646                                    );
 6647                                })
 6648                                .log_err();
 6649                        }
 6650                    })
 6651                })
 6652                .entry(set_breakpoint_msg, None, {
 6653                    let weak_editor = weak_editor.clone();
 6654                    let breakpoint = breakpoint.clone();
 6655                    move |_window, cx| {
 6656                        weak_editor
 6657                            .update(cx, |this, cx| {
 6658                                this.edit_breakpoint_at_anchor(
 6659                                    anchor,
 6660                                    breakpoint.as_ref().clone(),
 6661                                    BreakpointEditAction::Toggle,
 6662                                    cx,
 6663                                );
 6664                            })
 6665                            .log_err();
 6666                    }
 6667                })
 6668                .entry(log_breakpoint_msg, None, {
 6669                    let breakpoint = breakpoint.clone();
 6670                    let weak_editor = weak_editor.clone();
 6671                    move |window, cx| {
 6672                        weak_editor
 6673                            .update(cx, |this, cx| {
 6674                                this.add_edit_breakpoint_block(
 6675                                    anchor,
 6676                                    breakpoint.as_ref(),
 6677                                    BreakpointPromptEditAction::Log,
 6678                                    window,
 6679                                    cx,
 6680                                );
 6681                            })
 6682                            .log_err();
 6683                    }
 6684                })
 6685                .entry(condition_breakpoint_msg, None, {
 6686                    let breakpoint = breakpoint.clone();
 6687                    let weak_editor = weak_editor.clone();
 6688                    move |window, cx| {
 6689                        weak_editor
 6690                            .update(cx, |this, cx| {
 6691                                this.add_edit_breakpoint_block(
 6692                                    anchor,
 6693                                    breakpoint.as_ref(),
 6694                                    BreakpointPromptEditAction::Condition,
 6695                                    window,
 6696                                    cx,
 6697                                );
 6698                            })
 6699                            .log_err();
 6700                    }
 6701                })
 6702                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 6703                    weak_editor
 6704                        .update(cx, |this, cx| {
 6705                            this.add_edit_breakpoint_block(
 6706                                anchor,
 6707                                breakpoint.as_ref(),
 6708                                BreakpointPromptEditAction::HitCondition,
 6709                                window,
 6710                                cx,
 6711                            );
 6712                        })
 6713                        .log_err();
 6714                })
 6715        })
 6716    }
 6717
 6718    fn render_breakpoint(
 6719        &self,
 6720        position: Anchor,
 6721        row: DisplayRow,
 6722        breakpoint: &Breakpoint,
 6723        cx: &mut Context<Self>,
 6724    ) -> IconButton {
 6725        let (color, icon) = {
 6726            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 6727                (false, false) => ui::IconName::DebugBreakpoint,
 6728                (true, false) => ui::IconName::DebugLogBreakpoint,
 6729                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 6730                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 6731            };
 6732
 6733            let color = if self
 6734                .gutter_breakpoint_indicator
 6735                .0
 6736                .is_some_and(|(point, is_visible)| is_visible && point.row() == row)
 6737            {
 6738                Color::Hint
 6739            } else {
 6740                Color::Debugger
 6741            };
 6742
 6743            (color, icon)
 6744        };
 6745
 6746        let breakpoint = Arc::from(breakpoint.clone());
 6747
 6748        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 6749            .icon_size(IconSize::XSmall)
 6750            .size(ui::ButtonSize::None)
 6751            .icon_color(color)
 6752            .style(ButtonStyle::Transparent)
 6753            .on_click(cx.listener({
 6754                let breakpoint = breakpoint.clone();
 6755
 6756                move |editor, event: &ClickEvent, window, cx| {
 6757                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 6758                        BreakpointEditAction::InvertState
 6759                    } else {
 6760                        BreakpointEditAction::Toggle
 6761                    };
 6762
 6763                    window.focus(&editor.focus_handle(cx));
 6764                    editor.edit_breakpoint_at_anchor(
 6765                        position,
 6766                        breakpoint.as_ref().clone(),
 6767                        edit_action,
 6768                        cx,
 6769                    );
 6770                }
 6771            }))
 6772            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 6773                editor.set_breakpoint_context_menu(
 6774                    row,
 6775                    Some(position),
 6776                    event.down.position,
 6777                    window,
 6778                    cx,
 6779                );
 6780            }))
 6781    }
 6782
 6783    fn build_tasks_context(
 6784        project: &Entity<Project>,
 6785        buffer: &Entity<Buffer>,
 6786        buffer_row: u32,
 6787        tasks: &Arc<RunnableTasks>,
 6788        cx: &mut Context<Self>,
 6789    ) -> Task<Option<task::TaskContext>> {
 6790        let position = Point::new(buffer_row, tasks.column);
 6791        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 6792        let location = Location {
 6793            buffer: buffer.clone(),
 6794            range: range_start..range_start,
 6795        };
 6796        // Fill in the environmental variables from the tree-sitter captures
 6797        let mut captured_task_variables = TaskVariables::default();
 6798        for (capture_name, value) in tasks.extra_variables.clone() {
 6799            captured_task_variables.insert(
 6800                task::VariableName::Custom(capture_name.into()),
 6801                value.clone(),
 6802            );
 6803        }
 6804        project.update(cx, |project, cx| {
 6805            project.task_store().update(cx, |task_store, cx| {
 6806                task_store.task_context_for_location(captured_task_variables, location, cx)
 6807            })
 6808        })
 6809    }
 6810
 6811    pub fn spawn_nearest_task(
 6812        &mut self,
 6813        action: &SpawnNearestTask,
 6814        window: &mut Window,
 6815        cx: &mut Context<Self>,
 6816    ) {
 6817        let Some((workspace, _)) = self.workspace.clone() else {
 6818            return;
 6819        };
 6820        let Some(project) = self.project.clone() else {
 6821            return;
 6822        };
 6823
 6824        // Try to find a closest, enclosing node using tree-sitter that has a
 6825        // task
 6826        let Some((buffer, buffer_row, tasks)) = self
 6827            .find_enclosing_node_task(cx)
 6828            // Or find the task that's closest in row-distance.
 6829            .or_else(|| self.find_closest_task(cx))
 6830        else {
 6831            return;
 6832        };
 6833
 6834        let reveal_strategy = action.reveal;
 6835        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 6836        cx.spawn_in(window, async move |_, cx| {
 6837            let context = task_context.await?;
 6838            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 6839
 6840            let resolved = resolved_task.resolved.as_mut()?;
 6841            resolved.reveal = reveal_strategy;
 6842
 6843            workspace
 6844                .update_in(cx, |workspace, window, cx| {
 6845                    workspace.schedule_resolved_task(
 6846                        task_source_kind,
 6847                        resolved_task,
 6848                        false,
 6849                        window,
 6850                        cx,
 6851                    );
 6852                })
 6853                .ok()
 6854        })
 6855        .detach();
 6856    }
 6857
 6858    fn find_closest_task(
 6859        &mut self,
 6860        cx: &mut Context<Self>,
 6861    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 6862        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 6863
 6864        let ((buffer_id, row), tasks) = self
 6865            .tasks
 6866            .iter()
 6867            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 6868
 6869        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 6870        let tasks = Arc::new(tasks.to_owned());
 6871        Some((buffer, *row, tasks))
 6872    }
 6873
 6874    fn find_enclosing_node_task(
 6875        &mut self,
 6876        cx: &mut Context<Self>,
 6877    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 6878        let snapshot = self.buffer.read(cx).snapshot(cx);
 6879        let offset = self.selections.newest::<usize>(cx).head();
 6880        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 6881        let buffer_id = excerpt.buffer().remote_id();
 6882
 6883        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 6884        let mut cursor = layer.node().walk();
 6885
 6886        while cursor.goto_first_child_for_byte(offset).is_some() {
 6887            if cursor.node().end_byte() == offset {
 6888                cursor.goto_next_sibling();
 6889            }
 6890        }
 6891
 6892        // Ascend to the smallest ancestor that contains the range and has a task.
 6893        loop {
 6894            let node = cursor.node();
 6895            let node_range = node.byte_range();
 6896            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 6897
 6898            // Check if this node contains our offset
 6899            if node_range.start <= offset && node_range.end >= offset {
 6900                // If it contains offset, check for task
 6901                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 6902                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 6903                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 6904                }
 6905            }
 6906
 6907            if !cursor.goto_parent() {
 6908                break;
 6909            }
 6910        }
 6911        None
 6912    }
 6913
 6914    fn render_run_indicator(
 6915        &self,
 6916        _style: &EditorStyle,
 6917        is_active: bool,
 6918        row: DisplayRow,
 6919        breakpoint: Option<(Anchor, Breakpoint)>,
 6920        cx: &mut Context<Self>,
 6921    ) -> IconButton {
 6922        let color = Color::Muted;
 6923        let position = breakpoint.as_ref().map(|(anchor, _)| *anchor);
 6924
 6925        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 6926            .shape(ui::IconButtonShape::Square)
 6927            .icon_size(IconSize::XSmall)
 6928            .icon_color(color)
 6929            .toggle_state(is_active)
 6930            .on_click(cx.listener(move |editor, _e, window, cx| {
 6931                window.focus(&editor.focus_handle(cx));
 6932                editor.toggle_code_actions(
 6933                    &ToggleCodeActions {
 6934                        deployed_from_indicator: Some(row),
 6935                    },
 6936                    window,
 6937                    cx,
 6938                );
 6939            }))
 6940            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 6941                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 6942            }))
 6943    }
 6944
 6945    pub fn context_menu_visible(&self) -> bool {
 6946        !self.edit_prediction_preview_is_active()
 6947            && self
 6948                .context_menu
 6949                .borrow()
 6950                .as_ref()
 6951                .map_or(false, |menu| menu.visible())
 6952    }
 6953
 6954    fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 6955        self.context_menu
 6956            .borrow()
 6957            .as_ref()
 6958            .map(|menu| menu.origin())
 6959    }
 6960
 6961    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 6962        self.context_menu_options = Some(options);
 6963    }
 6964
 6965    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 6966    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 6967
 6968    fn render_edit_prediction_popover(
 6969        &mut self,
 6970        text_bounds: &Bounds<Pixels>,
 6971        content_origin: gpui::Point<Pixels>,
 6972        editor_snapshot: &EditorSnapshot,
 6973        visible_row_range: Range<DisplayRow>,
 6974        scroll_top: f32,
 6975        scroll_bottom: f32,
 6976        line_layouts: &[LineWithInvisibles],
 6977        line_height: Pixels,
 6978        scroll_pixel_position: gpui::Point<Pixels>,
 6979        newest_selection_head: Option<DisplayPoint>,
 6980        editor_width: Pixels,
 6981        style: &EditorStyle,
 6982        window: &mut Window,
 6983        cx: &mut App,
 6984    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 6985        let active_inline_completion = self.active_inline_completion.as_ref()?;
 6986
 6987        if self.edit_prediction_visible_in_cursor_popover(true) {
 6988            return None;
 6989        }
 6990
 6991        match &active_inline_completion.completion {
 6992            InlineCompletion::Move { target, .. } => {
 6993                let target_display_point = target.to_display_point(editor_snapshot);
 6994
 6995                if self.edit_prediction_requires_modifier() {
 6996                    if !self.edit_prediction_preview_is_active() {
 6997                        return None;
 6998                    }
 6999
 7000                    self.render_edit_prediction_modifier_jump_popover(
 7001                        text_bounds,
 7002                        content_origin,
 7003                        visible_row_range,
 7004                        line_layouts,
 7005                        line_height,
 7006                        scroll_pixel_position,
 7007                        newest_selection_head,
 7008                        target_display_point,
 7009                        window,
 7010                        cx,
 7011                    )
 7012                } else {
 7013                    self.render_edit_prediction_eager_jump_popover(
 7014                        text_bounds,
 7015                        content_origin,
 7016                        editor_snapshot,
 7017                        visible_row_range,
 7018                        scroll_top,
 7019                        scroll_bottom,
 7020                        line_height,
 7021                        scroll_pixel_position,
 7022                        target_display_point,
 7023                        editor_width,
 7024                        window,
 7025                        cx,
 7026                    )
 7027                }
 7028            }
 7029            InlineCompletion::Edit {
 7030                display_mode: EditDisplayMode::Inline,
 7031                ..
 7032            } => None,
 7033            InlineCompletion::Edit {
 7034                display_mode: EditDisplayMode::TabAccept,
 7035                edits,
 7036                ..
 7037            } => {
 7038                let range = &edits.first()?.0;
 7039                let target_display_point = range.end.to_display_point(editor_snapshot);
 7040
 7041                self.render_edit_prediction_end_of_line_popover(
 7042                    "Accept",
 7043                    editor_snapshot,
 7044                    visible_row_range,
 7045                    target_display_point,
 7046                    line_height,
 7047                    scroll_pixel_position,
 7048                    content_origin,
 7049                    editor_width,
 7050                    window,
 7051                    cx,
 7052                )
 7053            }
 7054            InlineCompletion::Edit {
 7055                edits,
 7056                edit_preview,
 7057                display_mode: EditDisplayMode::DiffPopover,
 7058                snapshot,
 7059            } => self.render_edit_prediction_diff_popover(
 7060                text_bounds,
 7061                content_origin,
 7062                editor_snapshot,
 7063                visible_row_range,
 7064                line_layouts,
 7065                line_height,
 7066                scroll_pixel_position,
 7067                newest_selection_head,
 7068                editor_width,
 7069                style,
 7070                edits,
 7071                edit_preview,
 7072                snapshot,
 7073                window,
 7074                cx,
 7075            ),
 7076        }
 7077    }
 7078
 7079    fn render_edit_prediction_modifier_jump_popover(
 7080        &mut self,
 7081        text_bounds: &Bounds<Pixels>,
 7082        content_origin: gpui::Point<Pixels>,
 7083        visible_row_range: Range<DisplayRow>,
 7084        line_layouts: &[LineWithInvisibles],
 7085        line_height: Pixels,
 7086        scroll_pixel_position: gpui::Point<Pixels>,
 7087        newest_selection_head: Option<DisplayPoint>,
 7088        target_display_point: DisplayPoint,
 7089        window: &mut Window,
 7090        cx: &mut App,
 7091    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7092        let scrolled_content_origin =
 7093            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 7094
 7095        const SCROLL_PADDING_Y: Pixels = px(12.);
 7096
 7097        if target_display_point.row() < visible_row_range.start {
 7098            return self.render_edit_prediction_scroll_popover(
 7099                |_| SCROLL_PADDING_Y,
 7100                IconName::ArrowUp,
 7101                visible_row_range,
 7102                line_layouts,
 7103                newest_selection_head,
 7104                scrolled_content_origin,
 7105                window,
 7106                cx,
 7107            );
 7108        } else if target_display_point.row() >= visible_row_range.end {
 7109            return self.render_edit_prediction_scroll_popover(
 7110                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 7111                IconName::ArrowDown,
 7112                visible_row_range,
 7113                line_layouts,
 7114                newest_selection_head,
 7115                scrolled_content_origin,
 7116                window,
 7117                cx,
 7118            );
 7119        }
 7120
 7121        const POLE_WIDTH: Pixels = px(2.);
 7122
 7123        let line_layout =
 7124            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 7125        let target_column = target_display_point.column() as usize;
 7126
 7127        let target_x = line_layout.x_for_index(target_column);
 7128        let target_y =
 7129            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 7130
 7131        let flag_on_right = target_x < text_bounds.size.width / 2.;
 7132
 7133        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 7134        border_color.l += 0.001;
 7135
 7136        let mut element = v_flex()
 7137            .items_end()
 7138            .when(flag_on_right, |el| el.items_start())
 7139            .child(if flag_on_right {
 7140                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7141                    .rounded_bl(px(0.))
 7142                    .rounded_tl(px(0.))
 7143                    .border_l_2()
 7144                    .border_color(border_color)
 7145            } else {
 7146                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7147                    .rounded_br(px(0.))
 7148                    .rounded_tr(px(0.))
 7149                    .border_r_2()
 7150                    .border_color(border_color)
 7151            })
 7152            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 7153            .into_any();
 7154
 7155        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7156
 7157        let mut origin = scrolled_content_origin + point(target_x, target_y)
 7158            - point(
 7159                if flag_on_right {
 7160                    POLE_WIDTH
 7161                } else {
 7162                    size.width - POLE_WIDTH
 7163                },
 7164                size.height - line_height,
 7165            );
 7166
 7167        origin.x = origin.x.max(content_origin.x);
 7168
 7169        element.prepaint_at(origin, window, cx);
 7170
 7171        Some((element, origin))
 7172    }
 7173
 7174    fn render_edit_prediction_scroll_popover(
 7175        &mut self,
 7176        to_y: impl Fn(Size<Pixels>) -> Pixels,
 7177        scroll_icon: IconName,
 7178        visible_row_range: Range<DisplayRow>,
 7179        line_layouts: &[LineWithInvisibles],
 7180        newest_selection_head: Option<DisplayPoint>,
 7181        scrolled_content_origin: gpui::Point<Pixels>,
 7182        window: &mut Window,
 7183        cx: &mut App,
 7184    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7185        let mut element = self
 7186            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 7187            .into_any();
 7188
 7189        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7190
 7191        let cursor = newest_selection_head?;
 7192        let cursor_row_layout =
 7193            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 7194        let cursor_column = cursor.column() as usize;
 7195
 7196        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 7197
 7198        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 7199
 7200        element.prepaint_at(origin, window, cx);
 7201        Some((element, origin))
 7202    }
 7203
 7204    fn render_edit_prediction_eager_jump_popover(
 7205        &mut self,
 7206        text_bounds: &Bounds<Pixels>,
 7207        content_origin: gpui::Point<Pixels>,
 7208        editor_snapshot: &EditorSnapshot,
 7209        visible_row_range: Range<DisplayRow>,
 7210        scroll_top: f32,
 7211        scroll_bottom: f32,
 7212        line_height: Pixels,
 7213        scroll_pixel_position: gpui::Point<Pixels>,
 7214        target_display_point: DisplayPoint,
 7215        editor_width: Pixels,
 7216        window: &mut Window,
 7217        cx: &mut App,
 7218    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7219        if target_display_point.row().as_f32() < scroll_top {
 7220            let mut element = self
 7221                .render_edit_prediction_line_popover(
 7222                    "Jump to Edit",
 7223                    Some(IconName::ArrowUp),
 7224                    window,
 7225                    cx,
 7226                )?
 7227                .into_any();
 7228
 7229            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7230            let offset = point(
 7231                (text_bounds.size.width - size.width) / 2.,
 7232                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7233            );
 7234
 7235            let origin = text_bounds.origin + offset;
 7236            element.prepaint_at(origin, window, cx);
 7237            Some((element, origin))
 7238        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 7239            let mut element = self
 7240                .render_edit_prediction_line_popover(
 7241                    "Jump to Edit",
 7242                    Some(IconName::ArrowDown),
 7243                    window,
 7244                    cx,
 7245                )?
 7246                .into_any();
 7247
 7248            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7249            let offset = point(
 7250                (text_bounds.size.width - size.width) / 2.,
 7251                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7252            );
 7253
 7254            let origin = text_bounds.origin + offset;
 7255            element.prepaint_at(origin, window, cx);
 7256            Some((element, origin))
 7257        } else {
 7258            self.render_edit_prediction_end_of_line_popover(
 7259                "Jump to Edit",
 7260                editor_snapshot,
 7261                visible_row_range,
 7262                target_display_point,
 7263                line_height,
 7264                scroll_pixel_position,
 7265                content_origin,
 7266                editor_width,
 7267                window,
 7268                cx,
 7269            )
 7270        }
 7271    }
 7272
 7273    fn render_edit_prediction_end_of_line_popover(
 7274        self: &mut Editor,
 7275        label: &'static str,
 7276        editor_snapshot: &EditorSnapshot,
 7277        visible_row_range: Range<DisplayRow>,
 7278        target_display_point: DisplayPoint,
 7279        line_height: Pixels,
 7280        scroll_pixel_position: gpui::Point<Pixels>,
 7281        content_origin: gpui::Point<Pixels>,
 7282        editor_width: Pixels,
 7283        window: &mut Window,
 7284        cx: &mut App,
 7285    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7286        let target_line_end = DisplayPoint::new(
 7287            target_display_point.row(),
 7288            editor_snapshot.line_len(target_display_point.row()),
 7289        );
 7290
 7291        let mut element = self
 7292            .render_edit_prediction_line_popover(label, None, window, cx)?
 7293            .into_any();
 7294
 7295        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7296
 7297        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 7298
 7299        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 7300        let mut origin = start_point
 7301            + line_origin
 7302            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 7303        origin.x = origin.x.max(content_origin.x);
 7304
 7305        let max_x = content_origin.x + editor_width - size.width;
 7306
 7307        if origin.x > max_x {
 7308            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 7309
 7310            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 7311                origin.y += offset;
 7312                IconName::ArrowUp
 7313            } else {
 7314                origin.y -= offset;
 7315                IconName::ArrowDown
 7316            };
 7317
 7318            element = self
 7319                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 7320                .into_any();
 7321
 7322            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7323
 7324            origin.x = content_origin.x + editor_width - size.width - px(2.);
 7325        }
 7326
 7327        element.prepaint_at(origin, window, cx);
 7328        Some((element, origin))
 7329    }
 7330
 7331    fn render_edit_prediction_diff_popover(
 7332        self: &Editor,
 7333        text_bounds: &Bounds<Pixels>,
 7334        content_origin: gpui::Point<Pixels>,
 7335        editor_snapshot: &EditorSnapshot,
 7336        visible_row_range: Range<DisplayRow>,
 7337        line_layouts: &[LineWithInvisibles],
 7338        line_height: Pixels,
 7339        scroll_pixel_position: gpui::Point<Pixels>,
 7340        newest_selection_head: Option<DisplayPoint>,
 7341        editor_width: Pixels,
 7342        style: &EditorStyle,
 7343        edits: &Vec<(Range<Anchor>, String)>,
 7344        edit_preview: &Option<language::EditPreview>,
 7345        snapshot: &language::BufferSnapshot,
 7346        window: &mut Window,
 7347        cx: &mut App,
 7348    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7349        let edit_start = edits
 7350            .first()
 7351            .unwrap()
 7352            .0
 7353            .start
 7354            .to_display_point(editor_snapshot);
 7355        let edit_end = edits
 7356            .last()
 7357            .unwrap()
 7358            .0
 7359            .end
 7360            .to_display_point(editor_snapshot);
 7361
 7362        let is_visible = visible_row_range.contains(&edit_start.row())
 7363            || visible_row_range.contains(&edit_end.row());
 7364        if !is_visible {
 7365            return None;
 7366        }
 7367
 7368        let highlighted_edits =
 7369            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 7370
 7371        let styled_text = highlighted_edits.to_styled_text(&style.text);
 7372        let line_count = highlighted_edits.text.lines().count();
 7373
 7374        const BORDER_WIDTH: Pixels = px(1.);
 7375
 7376        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 7377        let has_keybind = keybind.is_some();
 7378
 7379        let mut element = h_flex()
 7380            .items_start()
 7381            .child(
 7382                h_flex()
 7383                    .bg(cx.theme().colors().editor_background)
 7384                    .border(BORDER_WIDTH)
 7385                    .shadow_sm()
 7386                    .border_color(cx.theme().colors().border)
 7387                    .rounded_l_lg()
 7388                    .when(line_count > 1, |el| el.rounded_br_lg())
 7389                    .pr_1()
 7390                    .child(styled_text),
 7391            )
 7392            .child(
 7393                h_flex()
 7394                    .h(line_height + BORDER_WIDTH * 2.)
 7395                    .px_1p5()
 7396                    .gap_1()
 7397                    // Workaround: For some reason, there's a gap if we don't do this
 7398                    .ml(-BORDER_WIDTH)
 7399                    .shadow(smallvec![gpui::BoxShadow {
 7400                        color: gpui::black().opacity(0.05),
 7401                        offset: point(px(1.), px(1.)),
 7402                        blur_radius: px(2.),
 7403                        spread_radius: px(0.),
 7404                    }])
 7405                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 7406                    .border(BORDER_WIDTH)
 7407                    .border_color(cx.theme().colors().border)
 7408                    .rounded_r_lg()
 7409                    .id("edit_prediction_diff_popover_keybind")
 7410                    .when(!has_keybind, |el| {
 7411                        let status_colors = cx.theme().status();
 7412
 7413                        el.bg(status_colors.error_background)
 7414                            .border_color(status_colors.error.opacity(0.6))
 7415                            .child(Icon::new(IconName::Info).color(Color::Error))
 7416                            .cursor_default()
 7417                            .hoverable_tooltip(move |_window, cx| {
 7418                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 7419                            })
 7420                    })
 7421                    .children(keybind),
 7422            )
 7423            .into_any();
 7424
 7425        let longest_row =
 7426            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 7427        let longest_line_width = if visible_row_range.contains(&longest_row) {
 7428            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 7429        } else {
 7430            layout_line(
 7431                longest_row,
 7432                editor_snapshot,
 7433                style,
 7434                editor_width,
 7435                |_| false,
 7436                window,
 7437                cx,
 7438            )
 7439            .width
 7440        };
 7441
 7442        let viewport_bounds =
 7443            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 7444                right: -EditorElement::SCROLLBAR_WIDTH,
 7445                ..Default::default()
 7446            });
 7447
 7448        let x_after_longest =
 7449            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 7450                - scroll_pixel_position.x;
 7451
 7452        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7453
 7454        // Fully visible if it can be displayed within the window (allow overlapping other
 7455        // panes). However, this is only allowed if the popover starts within text_bounds.
 7456        let can_position_to_the_right = x_after_longest < text_bounds.right()
 7457            && x_after_longest + element_bounds.width < viewport_bounds.right();
 7458
 7459        let mut origin = if can_position_to_the_right {
 7460            point(
 7461                x_after_longest,
 7462                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 7463                    - scroll_pixel_position.y,
 7464            )
 7465        } else {
 7466            let cursor_row = newest_selection_head.map(|head| head.row());
 7467            let above_edit = edit_start
 7468                .row()
 7469                .0
 7470                .checked_sub(line_count as u32)
 7471                .map(DisplayRow);
 7472            let below_edit = Some(edit_end.row() + 1);
 7473            let above_cursor =
 7474                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 7475            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 7476
 7477            // Place the edit popover adjacent to the edit if there is a location
 7478            // available that is onscreen and does not obscure the cursor. Otherwise,
 7479            // place it adjacent to the cursor.
 7480            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 7481                .into_iter()
 7482                .flatten()
 7483                .find(|&start_row| {
 7484                    let end_row = start_row + line_count as u32;
 7485                    visible_row_range.contains(&start_row)
 7486                        && visible_row_range.contains(&end_row)
 7487                        && cursor_row.map_or(true, |cursor_row| {
 7488                            !((start_row..end_row).contains(&cursor_row))
 7489                        })
 7490                })?;
 7491
 7492            content_origin
 7493                + point(
 7494                    -scroll_pixel_position.x,
 7495                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 7496                )
 7497        };
 7498
 7499        origin.x -= BORDER_WIDTH;
 7500
 7501        window.defer_draw(element, origin, 1);
 7502
 7503        // Do not return an element, since it will already be drawn due to defer_draw.
 7504        None
 7505    }
 7506
 7507    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 7508        px(30.)
 7509    }
 7510
 7511    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 7512        if self.read_only(cx) {
 7513            cx.theme().players().read_only()
 7514        } else {
 7515            self.style.as_ref().unwrap().local_player
 7516        }
 7517    }
 7518
 7519    fn render_edit_prediction_accept_keybind(
 7520        &self,
 7521        window: &mut Window,
 7522        cx: &App,
 7523    ) -> Option<AnyElement> {
 7524        let accept_binding = self.accept_edit_prediction_keybind(window, cx);
 7525        let accept_keystroke = accept_binding.keystroke()?;
 7526
 7527        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 7528
 7529        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 7530            Color::Accent
 7531        } else {
 7532            Color::Muted
 7533        };
 7534
 7535        h_flex()
 7536            .px_0p5()
 7537            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 7538            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 7539            .text_size(TextSize::XSmall.rems(cx))
 7540            .child(h_flex().children(ui::render_modifiers(
 7541                &accept_keystroke.modifiers,
 7542                PlatformStyle::platform(),
 7543                Some(modifiers_color),
 7544                Some(IconSize::XSmall.rems().into()),
 7545                true,
 7546            )))
 7547            .when(is_platform_style_mac, |parent| {
 7548                parent.child(accept_keystroke.key.clone())
 7549            })
 7550            .when(!is_platform_style_mac, |parent| {
 7551                parent.child(
 7552                    Key::new(
 7553                        util::capitalize(&accept_keystroke.key),
 7554                        Some(Color::Default),
 7555                    )
 7556                    .size(Some(IconSize::XSmall.rems().into())),
 7557                )
 7558            })
 7559            .into_any()
 7560            .into()
 7561    }
 7562
 7563    fn render_edit_prediction_line_popover(
 7564        &self,
 7565        label: impl Into<SharedString>,
 7566        icon: Option<IconName>,
 7567        window: &mut Window,
 7568        cx: &App,
 7569    ) -> Option<Stateful<Div>> {
 7570        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 7571
 7572        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 7573        let has_keybind = keybind.is_some();
 7574
 7575        let result = h_flex()
 7576            .id("ep-line-popover")
 7577            .py_0p5()
 7578            .pl_1()
 7579            .pr(padding_right)
 7580            .gap_1()
 7581            .rounded_md()
 7582            .border_1()
 7583            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 7584            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 7585            .shadow_sm()
 7586            .when(!has_keybind, |el| {
 7587                let status_colors = cx.theme().status();
 7588
 7589                el.bg(status_colors.error_background)
 7590                    .border_color(status_colors.error.opacity(0.6))
 7591                    .pl_2()
 7592                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 7593                    .cursor_default()
 7594                    .hoverable_tooltip(move |_window, cx| {
 7595                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 7596                    })
 7597            })
 7598            .children(keybind)
 7599            .child(
 7600                Label::new(label)
 7601                    .size(LabelSize::Small)
 7602                    .when(!has_keybind, |el| {
 7603                        el.color(cx.theme().status().error.into()).strikethrough()
 7604                    }),
 7605            )
 7606            .when(!has_keybind, |el| {
 7607                el.child(
 7608                    h_flex().ml_1().child(
 7609                        Icon::new(IconName::Info)
 7610                            .size(IconSize::Small)
 7611                            .color(cx.theme().status().error.into()),
 7612                    ),
 7613                )
 7614            })
 7615            .when_some(icon, |element, icon| {
 7616                element.child(
 7617                    div()
 7618                        .mt(px(1.5))
 7619                        .child(Icon::new(icon).size(IconSize::Small)),
 7620                )
 7621            });
 7622
 7623        Some(result)
 7624    }
 7625
 7626    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 7627        let accent_color = cx.theme().colors().text_accent;
 7628        let editor_bg_color = cx.theme().colors().editor_background;
 7629        editor_bg_color.blend(accent_color.opacity(0.1))
 7630    }
 7631
 7632    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 7633        let accent_color = cx.theme().colors().text_accent;
 7634        let editor_bg_color = cx.theme().colors().editor_background;
 7635        editor_bg_color.blend(accent_color.opacity(0.6))
 7636    }
 7637
 7638    fn render_edit_prediction_cursor_popover(
 7639        &self,
 7640        min_width: Pixels,
 7641        max_width: Pixels,
 7642        cursor_point: Point,
 7643        style: &EditorStyle,
 7644        accept_keystroke: Option<&gpui::Keystroke>,
 7645        _window: &Window,
 7646        cx: &mut Context<Editor>,
 7647    ) -> Option<AnyElement> {
 7648        let provider = self.edit_prediction_provider.as_ref()?;
 7649
 7650        if provider.provider.needs_terms_acceptance(cx) {
 7651            return Some(
 7652                h_flex()
 7653                    .min_w(min_width)
 7654                    .flex_1()
 7655                    .px_2()
 7656                    .py_1()
 7657                    .gap_3()
 7658                    .elevation_2(cx)
 7659                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 7660                    .id("accept-terms")
 7661                    .cursor_pointer()
 7662                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 7663                    .on_click(cx.listener(|this, _event, window, cx| {
 7664                        cx.stop_propagation();
 7665                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 7666                        window.dispatch_action(
 7667                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 7668                            cx,
 7669                        );
 7670                    }))
 7671                    .child(
 7672                        h_flex()
 7673                            .flex_1()
 7674                            .gap_2()
 7675                            .child(Icon::new(IconName::ZedPredict))
 7676                            .child(Label::new("Accept Terms of Service"))
 7677                            .child(div().w_full())
 7678                            .child(
 7679                                Icon::new(IconName::ArrowUpRight)
 7680                                    .color(Color::Muted)
 7681                                    .size(IconSize::Small),
 7682                            )
 7683                            .into_any_element(),
 7684                    )
 7685                    .into_any(),
 7686            );
 7687        }
 7688
 7689        let is_refreshing = provider.provider.is_refreshing(cx);
 7690
 7691        fn pending_completion_container() -> Div {
 7692            h_flex()
 7693                .h_full()
 7694                .flex_1()
 7695                .gap_2()
 7696                .child(Icon::new(IconName::ZedPredict))
 7697        }
 7698
 7699        let completion = match &self.active_inline_completion {
 7700            Some(prediction) => {
 7701                if !self.has_visible_completions_menu() {
 7702                    const RADIUS: Pixels = px(6.);
 7703                    const BORDER_WIDTH: Pixels = px(1.);
 7704
 7705                    return Some(
 7706                        h_flex()
 7707                            .elevation_2(cx)
 7708                            .border(BORDER_WIDTH)
 7709                            .border_color(cx.theme().colors().border)
 7710                            .when(accept_keystroke.is_none(), |el| {
 7711                                el.border_color(cx.theme().status().error)
 7712                            })
 7713                            .rounded(RADIUS)
 7714                            .rounded_tl(px(0.))
 7715                            .overflow_hidden()
 7716                            .child(div().px_1p5().child(match &prediction.completion {
 7717                                InlineCompletion::Move { target, snapshot } => {
 7718                                    use text::ToPoint as _;
 7719                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 7720                                    {
 7721                                        Icon::new(IconName::ZedPredictDown)
 7722                                    } else {
 7723                                        Icon::new(IconName::ZedPredictUp)
 7724                                    }
 7725                                }
 7726                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 7727                            }))
 7728                            .child(
 7729                                h_flex()
 7730                                    .gap_1()
 7731                                    .py_1()
 7732                                    .px_2()
 7733                                    .rounded_r(RADIUS - BORDER_WIDTH)
 7734                                    .border_l_1()
 7735                                    .border_color(cx.theme().colors().border)
 7736                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 7737                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 7738                                        el.child(
 7739                                            Label::new("Hold")
 7740                                                .size(LabelSize::Small)
 7741                                                .when(accept_keystroke.is_none(), |el| {
 7742                                                    el.strikethrough()
 7743                                                })
 7744                                                .line_height_style(LineHeightStyle::UiLabel),
 7745                                        )
 7746                                    })
 7747                                    .id("edit_prediction_cursor_popover_keybind")
 7748                                    .when(accept_keystroke.is_none(), |el| {
 7749                                        let status_colors = cx.theme().status();
 7750
 7751                                        el.bg(status_colors.error_background)
 7752                                            .border_color(status_colors.error.opacity(0.6))
 7753                                            .child(Icon::new(IconName::Info).color(Color::Error))
 7754                                            .cursor_default()
 7755                                            .hoverable_tooltip(move |_window, cx| {
 7756                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 7757                                                    .into()
 7758                                            })
 7759                                    })
 7760                                    .when_some(
 7761                                        accept_keystroke.as_ref(),
 7762                                        |el, accept_keystroke| {
 7763                                            el.child(h_flex().children(ui::render_modifiers(
 7764                                                &accept_keystroke.modifiers,
 7765                                                PlatformStyle::platform(),
 7766                                                Some(Color::Default),
 7767                                                Some(IconSize::XSmall.rems().into()),
 7768                                                false,
 7769                                            )))
 7770                                        },
 7771                                    ),
 7772                            )
 7773                            .into_any(),
 7774                    );
 7775                }
 7776
 7777                self.render_edit_prediction_cursor_popover_preview(
 7778                    prediction,
 7779                    cursor_point,
 7780                    style,
 7781                    cx,
 7782                )?
 7783            }
 7784
 7785            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 7786                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 7787                    stale_completion,
 7788                    cursor_point,
 7789                    style,
 7790                    cx,
 7791                )?,
 7792
 7793                None => {
 7794                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 7795                }
 7796            },
 7797
 7798            None => pending_completion_container().child(Label::new("No Prediction")),
 7799        };
 7800
 7801        let completion = if is_refreshing {
 7802            completion
 7803                .with_animation(
 7804                    "loading-completion",
 7805                    Animation::new(Duration::from_secs(2))
 7806                        .repeat()
 7807                        .with_easing(pulsating_between(0.4, 0.8)),
 7808                    |label, delta| label.opacity(delta),
 7809                )
 7810                .into_any_element()
 7811        } else {
 7812            completion.into_any_element()
 7813        };
 7814
 7815        let has_completion = self.active_inline_completion.is_some();
 7816
 7817        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 7818        Some(
 7819            h_flex()
 7820                .min_w(min_width)
 7821                .max_w(max_width)
 7822                .flex_1()
 7823                .elevation_2(cx)
 7824                .border_color(cx.theme().colors().border)
 7825                .child(
 7826                    div()
 7827                        .flex_1()
 7828                        .py_1()
 7829                        .px_2()
 7830                        .overflow_hidden()
 7831                        .child(completion),
 7832                )
 7833                .when_some(accept_keystroke, |el, accept_keystroke| {
 7834                    if !accept_keystroke.modifiers.modified() {
 7835                        return el;
 7836                    }
 7837
 7838                    el.child(
 7839                        h_flex()
 7840                            .h_full()
 7841                            .border_l_1()
 7842                            .rounded_r_lg()
 7843                            .border_color(cx.theme().colors().border)
 7844                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 7845                            .gap_1()
 7846                            .py_1()
 7847                            .px_2()
 7848                            .child(
 7849                                h_flex()
 7850                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 7851                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 7852                                    .child(h_flex().children(ui::render_modifiers(
 7853                                        &accept_keystroke.modifiers,
 7854                                        PlatformStyle::platform(),
 7855                                        Some(if !has_completion {
 7856                                            Color::Muted
 7857                                        } else {
 7858                                            Color::Default
 7859                                        }),
 7860                                        None,
 7861                                        false,
 7862                                    ))),
 7863                            )
 7864                            .child(Label::new("Preview").into_any_element())
 7865                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 7866                    )
 7867                })
 7868                .into_any(),
 7869        )
 7870    }
 7871
 7872    fn render_edit_prediction_cursor_popover_preview(
 7873        &self,
 7874        completion: &InlineCompletionState,
 7875        cursor_point: Point,
 7876        style: &EditorStyle,
 7877        cx: &mut Context<Editor>,
 7878    ) -> Option<Div> {
 7879        use text::ToPoint as _;
 7880
 7881        fn render_relative_row_jump(
 7882            prefix: impl Into<String>,
 7883            current_row: u32,
 7884            target_row: u32,
 7885        ) -> Div {
 7886            let (row_diff, arrow) = if target_row < current_row {
 7887                (current_row - target_row, IconName::ArrowUp)
 7888            } else {
 7889                (target_row - current_row, IconName::ArrowDown)
 7890            };
 7891
 7892            h_flex()
 7893                .child(
 7894                    Label::new(format!("{}{}", prefix.into(), row_diff))
 7895                        .color(Color::Muted)
 7896                        .size(LabelSize::Small),
 7897                )
 7898                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 7899        }
 7900
 7901        match &completion.completion {
 7902            InlineCompletion::Move {
 7903                target, snapshot, ..
 7904            } => Some(
 7905                h_flex()
 7906                    .px_2()
 7907                    .gap_2()
 7908                    .flex_1()
 7909                    .child(
 7910                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 7911                            Icon::new(IconName::ZedPredictDown)
 7912                        } else {
 7913                            Icon::new(IconName::ZedPredictUp)
 7914                        },
 7915                    )
 7916                    .child(Label::new("Jump to Edit")),
 7917            ),
 7918
 7919            InlineCompletion::Edit {
 7920                edits,
 7921                edit_preview,
 7922                snapshot,
 7923                display_mode: _,
 7924            } => {
 7925                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 7926
 7927                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 7928                    &snapshot,
 7929                    &edits,
 7930                    edit_preview.as_ref()?,
 7931                    true,
 7932                    cx,
 7933                )
 7934                .first_line_preview();
 7935
 7936                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 7937                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 7938
 7939                let preview = h_flex()
 7940                    .gap_1()
 7941                    .min_w_16()
 7942                    .child(styled_text)
 7943                    .when(has_more_lines, |parent| parent.child(""));
 7944
 7945                let left = if first_edit_row != cursor_point.row {
 7946                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 7947                        .into_any_element()
 7948                } else {
 7949                    Icon::new(IconName::ZedPredict).into_any_element()
 7950                };
 7951
 7952                Some(
 7953                    h_flex()
 7954                        .h_full()
 7955                        .flex_1()
 7956                        .gap_2()
 7957                        .pr_1()
 7958                        .overflow_x_hidden()
 7959                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 7960                        .child(left)
 7961                        .child(preview),
 7962                )
 7963            }
 7964        }
 7965    }
 7966
 7967    fn render_context_menu(
 7968        &self,
 7969        style: &EditorStyle,
 7970        max_height_in_lines: u32,
 7971        window: &mut Window,
 7972        cx: &mut Context<Editor>,
 7973    ) -> Option<AnyElement> {
 7974        let menu = self.context_menu.borrow();
 7975        let menu = menu.as_ref()?;
 7976        if !menu.visible() {
 7977            return None;
 7978        };
 7979        Some(menu.render(style, max_height_in_lines, window, cx))
 7980    }
 7981
 7982    fn render_context_menu_aside(
 7983        &mut self,
 7984        max_size: Size<Pixels>,
 7985        window: &mut Window,
 7986        cx: &mut Context<Editor>,
 7987    ) -> Option<AnyElement> {
 7988        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 7989            if menu.visible() {
 7990                menu.render_aside(self, max_size, window, cx)
 7991            } else {
 7992                None
 7993            }
 7994        })
 7995    }
 7996
 7997    fn hide_context_menu(
 7998        &mut self,
 7999        window: &mut Window,
 8000        cx: &mut Context<Self>,
 8001    ) -> Option<CodeContextMenu> {
 8002        cx.notify();
 8003        self.completion_tasks.clear();
 8004        let context_menu = self.context_menu.borrow_mut().take();
 8005        self.stale_inline_completion_in_menu.take();
 8006        self.update_visible_inline_completion(window, cx);
 8007        context_menu
 8008    }
 8009
 8010    fn show_snippet_choices(
 8011        &mut self,
 8012        choices: &Vec<String>,
 8013        selection: Range<Anchor>,
 8014        cx: &mut Context<Self>,
 8015    ) {
 8016        if selection.start.buffer_id.is_none() {
 8017            return;
 8018        }
 8019        let buffer_id = selection.start.buffer_id.unwrap();
 8020        let buffer = self.buffer().read(cx).buffer(buffer_id);
 8021        let id = post_inc(&mut self.next_completion_id);
 8022        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 8023
 8024        if let Some(buffer) = buffer {
 8025            *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 8026                CompletionsMenu::new_snippet_choices(
 8027                    id,
 8028                    true,
 8029                    choices,
 8030                    selection,
 8031                    buffer,
 8032                    snippet_sort_order,
 8033                ),
 8034            ));
 8035        }
 8036    }
 8037
 8038    pub fn insert_snippet(
 8039        &mut self,
 8040        insertion_ranges: &[Range<usize>],
 8041        snippet: Snippet,
 8042        window: &mut Window,
 8043        cx: &mut Context<Self>,
 8044    ) -> Result<()> {
 8045        struct Tabstop<T> {
 8046            is_end_tabstop: bool,
 8047            ranges: Vec<Range<T>>,
 8048            choices: Option<Vec<String>>,
 8049        }
 8050
 8051        let tabstops = self.buffer.update(cx, |buffer, cx| {
 8052            let snippet_text: Arc<str> = snippet.text.clone().into();
 8053            let edits = insertion_ranges
 8054                .iter()
 8055                .cloned()
 8056                .map(|range| (range, snippet_text.clone()));
 8057            buffer.edit(edits, Some(AutoindentMode::EachLine), cx);
 8058
 8059            let snapshot = &*buffer.read(cx);
 8060            let snippet = &snippet;
 8061            snippet
 8062                .tabstops
 8063                .iter()
 8064                .map(|tabstop| {
 8065                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 8066                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 8067                    });
 8068                    let mut tabstop_ranges = tabstop
 8069                        .ranges
 8070                        .iter()
 8071                        .flat_map(|tabstop_range| {
 8072                            let mut delta = 0_isize;
 8073                            insertion_ranges.iter().map(move |insertion_range| {
 8074                                let insertion_start = insertion_range.start as isize + delta;
 8075                                delta +=
 8076                                    snippet.text.len() as isize - insertion_range.len() as isize;
 8077
 8078                                let start = ((insertion_start + tabstop_range.start) as usize)
 8079                                    .min(snapshot.len());
 8080                                let end = ((insertion_start + tabstop_range.end) as usize)
 8081                                    .min(snapshot.len());
 8082                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 8083                            })
 8084                        })
 8085                        .collect::<Vec<_>>();
 8086                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 8087
 8088                    Tabstop {
 8089                        is_end_tabstop,
 8090                        ranges: tabstop_ranges,
 8091                        choices: tabstop.choices.clone(),
 8092                    }
 8093                })
 8094                .collect::<Vec<_>>()
 8095        });
 8096        if let Some(tabstop) = tabstops.first() {
 8097            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8098                s.select_ranges(tabstop.ranges.iter().cloned());
 8099            });
 8100
 8101            if let Some(choices) = &tabstop.choices {
 8102                if let Some(selection) = tabstop.ranges.first() {
 8103                    self.show_snippet_choices(choices, selection.clone(), cx)
 8104                }
 8105            }
 8106
 8107            // If we're already at the last tabstop and it's at the end of the snippet,
 8108            // we're done, we don't need to keep the state around.
 8109            if !tabstop.is_end_tabstop {
 8110                let choices = tabstops
 8111                    .iter()
 8112                    .map(|tabstop| tabstop.choices.clone())
 8113                    .collect();
 8114
 8115                let ranges = tabstops
 8116                    .into_iter()
 8117                    .map(|tabstop| tabstop.ranges)
 8118                    .collect::<Vec<_>>();
 8119
 8120                self.snippet_stack.push(SnippetState {
 8121                    active_index: 0,
 8122                    ranges,
 8123                    choices,
 8124                });
 8125            }
 8126
 8127            // Check whether the just-entered snippet ends with an auto-closable bracket.
 8128            if self.autoclose_regions.is_empty() {
 8129                let snapshot = self.buffer.read(cx).snapshot(cx);
 8130                for selection in &mut self.selections.all::<Point>(cx) {
 8131                    let selection_head = selection.head();
 8132                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 8133                        continue;
 8134                    };
 8135
 8136                    let mut bracket_pair = None;
 8137                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 8138                    let prev_chars = snapshot
 8139                        .reversed_chars_at(selection_head)
 8140                        .collect::<String>();
 8141                    for (pair, enabled) in scope.brackets() {
 8142                        if enabled
 8143                            && pair.close
 8144                            && prev_chars.starts_with(pair.start.as_str())
 8145                            && next_chars.starts_with(pair.end.as_str())
 8146                        {
 8147                            bracket_pair = Some(pair.clone());
 8148                            break;
 8149                        }
 8150                    }
 8151                    if let Some(pair) = bracket_pair {
 8152                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 8153                        let autoclose_enabled =
 8154                            self.use_autoclose && snapshot_settings.use_autoclose;
 8155                        if autoclose_enabled {
 8156                            let start = snapshot.anchor_after(selection_head);
 8157                            let end = snapshot.anchor_after(selection_head);
 8158                            self.autoclose_regions.push(AutocloseRegion {
 8159                                selection_id: selection.id,
 8160                                range: start..end,
 8161                                pair,
 8162                            });
 8163                        }
 8164                    }
 8165                }
 8166            }
 8167        }
 8168        Ok(())
 8169    }
 8170
 8171    pub fn move_to_next_snippet_tabstop(
 8172        &mut self,
 8173        window: &mut Window,
 8174        cx: &mut Context<Self>,
 8175    ) -> bool {
 8176        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 8177    }
 8178
 8179    pub fn move_to_prev_snippet_tabstop(
 8180        &mut self,
 8181        window: &mut Window,
 8182        cx: &mut Context<Self>,
 8183    ) -> bool {
 8184        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 8185    }
 8186
 8187    pub fn move_to_snippet_tabstop(
 8188        &mut self,
 8189        bias: Bias,
 8190        window: &mut Window,
 8191        cx: &mut Context<Self>,
 8192    ) -> bool {
 8193        if let Some(mut snippet) = self.snippet_stack.pop() {
 8194            match bias {
 8195                Bias::Left => {
 8196                    if snippet.active_index > 0 {
 8197                        snippet.active_index -= 1;
 8198                    } else {
 8199                        self.snippet_stack.push(snippet);
 8200                        return false;
 8201                    }
 8202                }
 8203                Bias::Right => {
 8204                    if snippet.active_index + 1 < snippet.ranges.len() {
 8205                        snippet.active_index += 1;
 8206                    } else {
 8207                        self.snippet_stack.push(snippet);
 8208                        return false;
 8209                    }
 8210                }
 8211            }
 8212            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 8213                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8214                    s.select_anchor_ranges(current_ranges.iter().cloned())
 8215                });
 8216
 8217                if let Some(choices) = &snippet.choices[snippet.active_index] {
 8218                    if let Some(selection) = current_ranges.first() {
 8219                        self.show_snippet_choices(&choices, selection.clone(), cx);
 8220                    }
 8221                }
 8222
 8223                // If snippet state is not at the last tabstop, push it back on the stack
 8224                if snippet.active_index + 1 < snippet.ranges.len() {
 8225                    self.snippet_stack.push(snippet);
 8226                }
 8227                return true;
 8228            }
 8229        }
 8230
 8231        false
 8232    }
 8233
 8234    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 8235        self.transact(window, cx, |this, window, cx| {
 8236            this.select_all(&SelectAll, window, cx);
 8237            this.insert("", window, cx);
 8238        });
 8239    }
 8240
 8241    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 8242        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8243        self.transact(window, cx, |this, window, cx| {
 8244            this.select_autoclose_pair(window, cx);
 8245            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 8246            if !this.linked_edit_ranges.is_empty() {
 8247                let selections = this.selections.all::<MultiBufferPoint>(cx);
 8248                let snapshot = this.buffer.read(cx).snapshot(cx);
 8249
 8250                for selection in selections.iter() {
 8251                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 8252                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 8253                    if selection_start.buffer_id != selection_end.buffer_id {
 8254                        continue;
 8255                    }
 8256                    if let Some(ranges) =
 8257                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 8258                    {
 8259                        for (buffer, entries) in ranges {
 8260                            linked_ranges.entry(buffer).or_default().extend(entries);
 8261                        }
 8262                    }
 8263                }
 8264            }
 8265
 8266            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 8267            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 8268            for selection in &mut selections {
 8269                if selection.is_empty() {
 8270                    let old_head = selection.head();
 8271                    let mut new_head =
 8272                        movement::left(&display_map, old_head.to_display_point(&display_map))
 8273                            .to_point(&display_map);
 8274                    if let Some((buffer, line_buffer_range)) = display_map
 8275                        .buffer_snapshot
 8276                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 8277                    {
 8278                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 8279                        let indent_len = match indent_size.kind {
 8280                            IndentKind::Space => {
 8281                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 8282                            }
 8283                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 8284                        };
 8285                        if old_head.column <= indent_size.len && old_head.column > 0 {
 8286                            let indent_len = indent_len.get();
 8287                            new_head = cmp::min(
 8288                                new_head,
 8289                                MultiBufferPoint::new(
 8290                                    old_head.row,
 8291                                    ((old_head.column - 1) / indent_len) * indent_len,
 8292                                ),
 8293                            );
 8294                        }
 8295                    }
 8296
 8297                    selection.set_head(new_head, SelectionGoal::None);
 8298                }
 8299            }
 8300
 8301            this.signature_help_state.set_backspace_pressed(true);
 8302            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8303                s.select(selections)
 8304            });
 8305            this.insert("", window, cx);
 8306            let empty_str: Arc<str> = Arc::from("");
 8307            for (buffer, edits) in linked_ranges {
 8308                let snapshot = buffer.read(cx).snapshot();
 8309                use text::ToPoint as TP;
 8310
 8311                let edits = edits
 8312                    .into_iter()
 8313                    .map(|range| {
 8314                        let end_point = TP::to_point(&range.end, &snapshot);
 8315                        let mut start_point = TP::to_point(&range.start, &snapshot);
 8316
 8317                        if end_point == start_point {
 8318                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 8319                                .saturating_sub(1);
 8320                            start_point =
 8321                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 8322                        };
 8323
 8324                        (start_point..end_point, empty_str.clone())
 8325                    })
 8326                    .sorted_by_key(|(range, _)| range.start)
 8327                    .collect::<Vec<_>>();
 8328                buffer.update(cx, |this, cx| {
 8329                    this.edit(edits, None, cx);
 8330                })
 8331            }
 8332            this.refresh_inline_completion(true, false, window, cx);
 8333            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 8334        });
 8335    }
 8336
 8337    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 8338        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8339        self.transact(window, cx, |this, window, cx| {
 8340            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8341                s.move_with(|map, selection| {
 8342                    if selection.is_empty() {
 8343                        let cursor = movement::right(map, selection.head());
 8344                        selection.end = cursor;
 8345                        selection.reversed = true;
 8346                        selection.goal = SelectionGoal::None;
 8347                    }
 8348                })
 8349            });
 8350            this.insert("", window, cx);
 8351            this.refresh_inline_completion(true, false, window, cx);
 8352        });
 8353    }
 8354
 8355    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 8356        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8357        if self.move_to_prev_snippet_tabstop(window, cx) {
 8358            return;
 8359        }
 8360        self.outdent(&Outdent, window, cx);
 8361    }
 8362
 8363    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 8364        if self.move_to_next_snippet_tabstop(window, cx) {
 8365            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8366            return;
 8367        }
 8368        if self.read_only(cx) {
 8369            return;
 8370        }
 8371        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8372        let mut selections = self.selections.all_adjusted(cx);
 8373        let buffer = self.buffer.read(cx);
 8374        let snapshot = buffer.snapshot(cx);
 8375        let rows_iter = selections.iter().map(|s| s.head().row);
 8376        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 8377
 8378        let mut edits = Vec::new();
 8379        let mut prev_edited_row = 0;
 8380        let mut row_delta = 0;
 8381        for selection in &mut selections {
 8382            if selection.start.row != prev_edited_row {
 8383                row_delta = 0;
 8384            }
 8385            prev_edited_row = selection.end.row;
 8386
 8387            // If the selection is non-empty, then increase the indentation of the selected lines.
 8388            if !selection.is_empty() {
 8389                row_delta =
 8390                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 8391                continue;
 8392            }
 8393
 8394            // If the selection is empty and the cursor is in the leading whitespace before the
 8395            // suggested indentation, then auto-indent the line.
 8396            let cursor = selection.head();
 8397            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 8398            if let Some(suggested_indent) =
 8399                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 8400            {
 8401                if cursor.column < suggested_indent.len
 8402                    && cursor.column <= current_indent.len
 8403                    && current_indent.len <= suggested_indent.len
 8404                {
 8405                    selection.start = Point::new(cursor.row, suggested_indent.len);
 8406                    selection.end = selection.start;
 8407                    if row_delta == 0 {
 8408                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 8409                            cursor.row,
 8410                            current_indent,
 8411                            suggested_indent,
 8412                        ));
 8413                        row_delta = suggested_indent.len - current_indent.len;
 8414                    }
 8415                    continue;
 8416                }
 8417            }
 8418
 8419            // Otherwise, insert a hard or soft tab.
 8420            let settings = buffer.language_settings_at(cursor, cx);
 8421            let tab_size = if settings.hard_tabs {
 8422                IndentSize::tab()
 8423            } else {
 8424                let tab_size = settings.tab_size.get();
 8425                let indent_remainder = snapshot
 8426                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 8427                    .flat_map(str::chars)
 8428                    .fold(row_delta % tab_size, |counter: u32, c| {
 8429                        if c == '\t' {
 8430                            0
 8431                        } else {
 8432                            (counter + 1) % tab_size
 8433                        }
 8434                    });
 8435
 8436                let chars_to_next_tab_stop = tab_size - indent_remainder;
 8437                IndentSize::spaces(chars_to_next_tab_stop)
 8438            };
 8439            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 8440            selection.end = selection.start;
 8441            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 8442            row_delta += tab_size.len;
 8443        }
 8444
 8445        self.transact(window, cx, |this, window, cx| {
 8446            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 8447            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8448                s.select(selections)
 8449            });
 8450            this.refresh_inline_completion(true, false, window, cx);
 8451        });
 8452    }
 8453
 8454    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 8455        if self.read_only(cx) {
 8456            return;
 8457        }
 8458        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8459        let mut selections = self.selections.all::<Point>(cx);
 8460        let mut prev_edited_row = 0;
 8461        let mut row_delta = 0;
 8462        let mut edits = Vec::new();
 8463        let buffer = self.buffer.read(cx);
 8464        let snapshot = buffer.snapshot(cx);
 8465        for selection in &mut selections {
 8466            if selection.start.row != prev_edited_row {
 8467                row_delta = 0;
 8468            }
 8469            prev_edited_row = selection.end.row;
 8470
 8471            row_delta =
 8472                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 8473        }
 8474
 8475        self.transact(window, cx, |this, window, cx| {
 8476            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 8477            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8478                s.select(selections)
 8479            });
 8480        });
 8481    }
 8482
 8483    fn indent_selection(
 8484        buffer: &MultiBuffer,
 8485        snapshot: &MultiBufferSnapshot,
 8486        selection: &mut Selection<Point>,
 8487        edits: &mut Vec<(Range<Point>, String)>,
 8488        delta_for_start_row: u32,
 8489        cx: &App,
 8490    ) -> u32 {
 8491        let settings = buffer.language_settings_at(selection.start, cx);
 8492        let tab_size = settings.tab_size.get();
 8493        let indent_kind = if settings.hard_tabs {
 8494            IndentKind::Tab
 8495        } else {
 8496            IndentKind::Space
 8497        };
 8498        let mut start_row = selection.start.row;
 8499        let mut end_row = selection.end.row + 1;
 8500
 8501        // If a selection ends at the beginning of a line, don't indent
 8502        // that last line.
 8503        if selection.end.column == 0 && selection.end.row > selection.start.row {
 8504            end_row -= 1;
 8505        }
 8506
 8507        // Avoid re-indenting a row that has already been indented by a
 8508        // previous selection, but still update this selection's column
 8509        // to reflect that indentation.
 8510        if delta_for_start_row > 0 {
 8511            start_row += 1;
 8512            selection.start.column += delta_for_start_row;
 8513            if selection.end.row == selection.start.row {
 8514                selection.end.column += delta_for_start_row;
 8515            }
 8516        }
 8517
 8518        let mut delta_for_end_row = 0;
 8519        let has_multiple_rows = start_row + 1 != end_row;
 8520        for row in start_row..end_row {
 8521            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 8522            let indent_delta = match (current_indent.kind, indent_kind) {
 8523                (IndentKind::Space, IndentKind::Space) => {
 8524                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 8525                    IndentSize::spaces(columns_to_next_tab_stop)
 8526                }
 8527                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 8528                (_, IndentKind::Tab) => IndentSize::tab(),
 8529            };
 8530
 8531            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 8532                0
 8533            } else {
 8534                selection.start.column
 8535            };
 8536            let row_start = Point::new(row, start);
 8537            edits.push((
 8538                row_start..row_start,
 8539                indent_delta.chars().collect::<String>(),
 8540            ));
 8541
 8542            // Update this selection's endpoints to reflect the indentation.
 8543            if row == selection.start.row {
 8544                selection.start.column += indent_delta.len;
 8545            }
 8546            if row == selection.end.row {
 8547                selection.end.column += indent_delta.len;
 8548                delta_for_end_row = indent_delta.len;
 8549            }
 8550        }
 8551
 8552        if selection.start.row == selection.end.row {
 8553            delta_for_start_row + delta_for_end_row
 8554        } else {
 8555            delta_for_end_row
 8556        }
 8557    }
 8558
 8559    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 8560        if self.read_only(cx) {
 8561            return;
 8562        }
 8563        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8564        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 8565        let selections = self.selections.all::<Point>(cx);
 8566        let mut deletion_ranges = Vec::new();
 8567        let mut last_outdent = None;
 8568        {
 8569            let buffer = self.buffer.read(cx);
 8570            let snapshot = buffer.snapshot(cx);
 8571            for selection in &selections {
 8572                let settings = buffer.language_settings_at(selection.start, cx);
 8573                let tab_size = settings.tab_size.get();
 8574                let mut rows = selection.spanned_rows(false, &display_map);
 8575
 8576                // Avoid re-outdenting a row that has already been outdented by a
 8577                // previous selection.
 8578                if let Some(last_row) = last_outdent {
 8579                    if last_row == rows.start {
 8580                        rows.start = rows.start.next_row();
 8581                    }
 8582                }
 8583                let has_multiple_rows = rows.len() > 1;
 8584                for row in rows.iter_rows() {
 8585                    let indent_size = snapshot.indent_size_for_line(row);
 8586                    if indent_size.len > 0 {
 8587                        let deletion_len = match indent_size.kind {
 8588                            IndentKind::Space => {
 8589                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 8590                                if columns_to_prev_tab_stop == 0 {
 8591                                    tab_size
 8592                                } else {
 8593                                    columns_to_prev_tab_stop
 8594                                }
 8595                            }
 8596                            IndentKind::Tab => 1,
 8597                        };
 8598                        let start = if has_multiple_rows
 8599                            || deletion_len > selection.start.column
 8600                            || indent_size.len < selection.start.column
 8601                        {
 8602                            0
 8603                        } else {
 8604                            selection.start.column - deletion_len
 8605                        };
 8606                        deletion_ranges.push(
 8607                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 8608                        );
 8609                        last_outdent = Some(row);
 8610                    }
 8611                }
 8612            }
 8613        }
 8614
 8615        self.transact(window, cx, |this, window, cx| {
 8616            this.buffer.update(cx, |buffer, cx| {
 8617                let empty_str: Arc<str> = Arc::default();
 8618                buffer.edit(
 8619                    deletion_ranges
 8620                        .into_iter()
 8621                        .map(|range| (range, empty_str.clone())),
 8622                    None,
 8623                    cx,
 8624                );
 8625            });
 8626            let selections = this.selections.all::<usize>(cx);
 8627            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8628                s.select(selections)
 8629            });
 8630        });
 8631    }
 8632
 8633    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 8634        if self.read_only(cx) {
 8635            return;
 8636        }
 8637        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8638        let selections = self
 8639            .selections
 8640            .all::<usize>(cx)
 8641            .into_iter()
 8642            .map(|s| s.range());
 8643
 8644        self.transact(window, cx, |this, window, cx| {
 8645            this.buffer.update(cx, |buffer, cx| {
 8646                buffer.autoindent_ranges(selections, cx);
 8647            });
 8648            let selections = this.selections.all::<usize>(cx);
 8649            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8650                s.select(selections)
 8651            });
 8652        });
 8653    }
 8654
 8655    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 8656        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8657        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 8658        let selections = self.selections.all::<Point>(cx);
 8659
 8660        let mut new_cursors = Vec::new();
 8661        let mut edit_ranges = Vec::new();
 8662        let mut selections = selections.iter().peekable();
 8663        while let Some(selection) = selections.next() {
 8664            let mut rows = selection.spanned_rows(false, &display_map);
 8665            let goal_display_column = selection.head().to_display_point(&display_map).column();
 8666
 8667            // Accumulate contiguous regions of rows that we want to delete.
 8668            while let Some(next_selection) = selections.peek() {
 8669                let next_rows = next_selection.spanned_rows(false, &display_map);
 8670                if next_rows.start <= rows.end {
 8671                    rows.end = next_rows.end;
 8672                    selections.next().unwrap();
 8673                } else {
 8674                    break;
 8675                }
 8676            }
 8677
 8678            let buffer = &display_map.buffer_snapshot;
 8679            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 8680            let edit_end;
 8681            let cursor_buffer_row;
 8682            if buffer.max_point().row >= rows.end.0 {
 8683                // If there's a line after the range, delete the \n from the end of the row range
 8684                // and position the cursor on the next line.
 8685                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 8686                cursor_buffer_row = rows.end;
 8687            } else {
 8688                // If there isn't a line after the range, delete the \n from the line before the
 8689                // start of the row range and position the cursor there.
 8690                edit_start = edit_start.saturating_sub(1);
 8691                edit_end = buffer.len();
 8692                cursor_buffer_row = rows.start.previous_row();
 8693            }
 8694
 8695            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 8696            *cursor.column_mut() =
 8697                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 8698
 8699            new_cursors.push((
 8700                selection.id,
 8701                buffer.anchor_after(cursor.to_point(&display_map)),
 8702            ));
 8703            edit_ranges.push(edit_start..edit_end);
 8704        }
 8705
 8706        self.transact(window, cx, |this, window, cx| {
 8707            let buffer = this.buffer.update(cx, |buffer, cx| {
 8708                let empty_str: Arc<str> = Arc::default();
 8709                buffer.edit(
 8710                    edit_ranges
 8711                        .into_iter()
 8712                        .map(|range| (range, empty_str.clone())),
 8713                    None,
 8714                    cx,
 8715                );
 8716                buffer.snapshot(cx)
 8717            });
 8718            let new_selections = new_cursors
 8719                .into_iter()
 8720                .map(|(id, cursor)| {
 8721                    let cursor = cursor.to_point(&buffer);
 8722                    Selection {
 8723                        id,
 8724                        start: cursor,
 8725                        end: cursor,
 8726                        reversed: false,
 8727                        goal: SelectionGoal::None,
 8728                    }
 8729                })
 8730                .collect();
 8731
 8732            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8733                s.select(new_selections);
 8734            });
 8735        });
 8736    }
 8737
 8738    pub fn join_lines_impl(
 8739        &mut self,
 8740        insert_whitespace: bool,
 8741        window: &mut Window,
 8742        cx: &mut Context<Self>,
 8743    ) {
 8744        if self.read_only(cx) {
 8745            return;
 8746        }
 8747        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 8748        for selection in self.selections.all::<Point>(cx) {
 8749            let start = MultiBufferRow(selection.start.row);
 8750            // Treat single line selections as if they include the next line. Otherwise this action
 8751            // would do nothing for single line selections individual cursors.
 8752            let end = if selection.start.row == selection.end.row {
 8753                MultiBufferRow(selection.start.row + 1)
 8754            } else {
 8755                MultiBufferRow(selection.end.row)
 8756            };
 8757
 8758            if let Some(last_row_range) = row_ranges.last_mut() {
 8759                if start <= last_row_range.end {
 8760                    last_row_range.end = end;
 8761                    continue;
 8762                }
 8763            }
 8764            row_ranges.push(start..end);
 8765        }
 8766
 8767        let snapshot = self.buffer.read(cx).snapshot(cx);
 8768        let mut cursor_positions = Vec::new();
 8769        for row_range in &row_ranges {
 8770            let anchor = snapshot.anchor_before(Point::new(
 8771                row_range.end.previous_row().0,
 8772                snapshot.line_len(row_range.end.previous_row()),
 8773            ));
 8774            cursor_positions.push(anchor..anchor);
 8775        }
 8776
 8777        self.transact(window, cx, |this, window, cx| {
 8778            for row_range in row_ranges.into_iter().rev() {
 8779                for row in row_range.iter_rows().rev() {
 8780                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 8781                    let next_line_row = row.next_row();
 8782                    let indent = snapshot.indent_size_for_line(next_line_row);
 8783                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 8784
 8785                    let replace =
 8786                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 8787                            " "
 8788                        } else {
 8789                            ""
 8790                        };
 8791
 8792                    this.buffer.update(cx, |buffer, cx| {
 8793                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 8794                    });
 8795                }
 8796            }
 8797
 8798            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8799                s.select_anchor_ranges(cursor_positions)
 8800            });
 8801        });
 8802    }
 8803
 8804    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 8805        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8806        self.join_lines_impl(true, window, cx);
 8807    }
 8808
 8809    pub fn sort_lines_case_sensitive(
 8810        &mut self,
 8811        _: &SortLinesCaseSensitive,
 8812        window: &mut Window,
 8813        cx: &mut Context<Self>,
 8814    ) {
 8815        self.manipulate_lines(window, cx, |lines| lines.sort())
 8816    }
 8817
 8818    pub fn sort_lines_case_insensitive(
 8819        &mut self,
 8820        _: &SortLinesCaseInsensitive,
 8821        window: &mut Window,
 8822        cx: &mut Context<Self>,
 8823    ) {
 8824        self.manipulate_lines(window, cx, |lines| {
 8825            lines.sort_by_key(|line| line.to_lowercase())
 8826        })
 8827    }
 8828
 8829    pub fn unique_lines_case_insensitive(
 8830        &mut self,
 8831        _: &UniqueLinesCaseInsensitive,
 8832        window: &mut Window,
 8833        cx: &mut Context<Self>,
 8834    ) {
 8835        self.manipulate_lines(window, cx, |lines| {
 8836            let mut seen = HashSet::default();
 8837            lines.retain(|line| seen.insert(line.to_lowercase()));
 8838        })
 8839    }
 8840
 8841    pub fn unique_lines_case_sensitive(
 8842        &mut self,
 8843        _: &UniqueLinesCaseSensitive,
 8844        window: &mut Window,
 8845        cx: &mut Context<Self>,
 8846    ) {
 8847        self.manipulate_lines(window, cx, |lines| {
 8848            let mut seen = HashSet::default();
 8849            lines.retain(|line| seen.insert(*line));
 8850        })
 8851    }
 8852
 8853    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 8854        let Some(project) = self.project.clone() else {
 8855            return;
 8856        };
 8857        self.reload(project, window, cx)
 8858            .detach_and_notify_err(window, cx);
 8859    }
 8860
 8861    pub fn restore_file(
 8862        &mut self,
 8863        _: &::git::RestoreFile,
 8864        window: &mut Window,
 8865        cx: &mut Context<Self>,
 8866    ) {
 8867        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8868        let mut buffer_ids = HashSet::default();
 8869        let snapshot = self.buffer().read(cx).snapshot(cx);
 8870        for selection in self.selections.all::<usize>(cx) {
 8871            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 8872        }
 8873
 8874        let buffer = self.buffer().read(cx);
 8875        let ranges = buffer_ids
 8876            .into_iter()
 8877            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 8878            .collect::<Vec<_>>();
 8879
 8880        self.restore_hunks_in_ranges(ranges, window, cx);
 8881    }
 8882
 8883    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 8884        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8885        let selections = self
 8886            .selections
 8887            .all(cx)
 8888            .into_iter()
 8889            .map(|s| s.range())
 8890            .collect();
 8891        self.restore_hunks_in_ranges(selections, window, cx);
 8892    }
 8893
 8894    pub fn restore_hunks_in_ranges(
 8895        &mut self,
 8896        ranges: Vec<Range<Point>>,
 8897        window: &mut Window,
 8898        cx: &mut Context<Editor>,
 8899    ) {
 8900        let mut revert_changes = HashMap::default();
 8901        let chunk_by = self
 8902            .snapshot(window, cx)
 8903            .hunks_for_ranges(ranges)
 8904            .into_iter()
 8905            .chunk_by(|hunk| hunk.buffer_id);
 8906        for (buffer_id, hunks) in &chunk_by {
 8907            let hunks = hunks.collect::<Vec<_>>();
 8908            for hunk in &hunks {
 8909                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 8910            }
 8911            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 8912        }
 8913        drop(chunk_by);
 8914        if !revert_changes.is_empty() {
 8915            self.transact(window, cx, |editor, window, cx| {
 8916                editor.restore(revert_changes, window, cx);
 8917            });
 8918        }
 8919    }
 8920
 8921    pub fn open_active_item_in_terminal(
 8922        &mut self,
 8923        _: &OpenInTerminal,
 8924        window: &mut Window,
 8925        cx: &mut Context<Self>,
 8926    ) {
 8927        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 8928            let project_path = buffer.read(cx).project_path(cx)?;
 8929            let project = self.project.as_ref()?.read(cx);
 8930            let entry = project.entry_for_path(&project_path, cx)?;
 8931            let parent = match &entry.canonical_path {
 8932                Some(canonical_path) => canonical_path.to_path_buf(),
 8933                None => project.absolute_path(&project_path, cx)?,
 8934            }
 8935            .parent()?
 8936            .to_path_buf();
 8937            Some(parent)
 8938        }) {
 8939            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 8940        }
 8941    }
 8942
 8943    fn set_breakpoint_context_menu(
 8944        &mut self,
 8945        display_row: DisplayRow,
 8946        position: Option<Anchor>,
 8947        clicked_point: gpui::Point<Pixels>,
 8948        window: &mut Window,
 8949        cx: &mut Context<Self>,
 8950    ) {
 8951        if !cx.has_flag::<DebuggerFeatureFlag>() {
 8952            return;
 8953        }
 8954        let source = self
 8955            .buffer
 8956            .read(cx)
 8957            .snapshot(cx)
 8958            .anchor_before(Point::new(display_row.0, 0u32));
 8959
 8960        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 8961
 8962        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
 8963            self,
 8964            source,
 8965            clicked_point,
 8966            context_menu,
 8967            window,
 8968            cx,
 8969        );
 8970    }
 8971
 8972    fn add_edit_breakpoint_block(
 8973        &mut self,
 8974        anchor: Anchor,
 8975        breakpoint: &Breakpoint,
 8976        edit_action: BreakpointPromptEditAction,
 8977        window: &mut Window,
 8978        cx: &mut Context<Self>,
 8979    ) {
 8980        let weak_editor = cx.weak_entity();
 8981        let bp_prompt = cx.new(|cx| {
 8982            BreakpointPromptEditor::new(
 8983                weak_editor,
 8984                anchor,
 8985                breakpoint.clone(),
 8986                edit_action,
 8987                window,
 8988                cx,
 8989            )
 8990        });
 8991
 8992        let height = bp_prompt.update(cx, |this, cx| {
 8993            this.prompt
 8994                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
 8995        });
 8996        let cloned_prompt = bp_prompt.clone();
 8997        let blocks = vec![BlockProperties {
 8998            style: BlockStyle::Sticky,
 8999            placement: BlockPlacement::Above(anchor),
 9000            height: Some(height),
 9001            render: Arc::new(move |cx| {
 9002                *cloned_prompt.read(cx).gutter_dimensions.lock() = *cx.gutter_dimensions;
 9003                cloned_prompt.clone().into_any_element()
 9004            }),
 9005            priority: 0,
 9006        }];
 9007
 9008        let focus_handle = bp_prompt.focus_handle(cx);
 9009        window.focus(&focus_handle);
 9010
 9011        let block_ids = self.insert_blocks(blocks, None, cx);
 9012        bp_prompt.update(cx, |prompt, _| {
 9013            prompt.add_block_ids(block_ids);
 9014        });
 9015    }
 9016
 9017    pub(crate) fn breakpoint_at_row(
 9018        &self,
 9019        row: u32,
 9020        window: &mut Window,
 9021        cx: &mut Context<Self>,
 9022    ) -> Option<(Anchor, Breakpoint)> {
 9023        let snapshot = self.snapshot(window, cx);
 9024        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
 9025
 9026        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9027    }
 9028
 9029    pub(crate) fn breakpoint_at_anchor(
 9030        &self,
 9031        breakpoint_position: Anchor,
 9032        snapshot: &EditorSnapshot,
 9033        cx: &mut Context<Self>,
 9034    ) -> Option<(Anchor, Breakpoint)> {
 9035        let project = self.project.clone()?;
 9036
 9037        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
 9038            snapshot
 9039                .buffer_snapshot
 9040                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
 9041        })?;
 9042
 9043        let enclosing_excerpt = breakpoint_position.excerpt_id;
 9044        let buffer = project.read_with(cx, |project, cx| project.buffer_for_id(buffer_id, cx))?;
 9045        let buffer_snapshot = buffer.read(cx).snapshot();
 9046
 9047        let row = buffer_snapshot
 9048            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
 9049            .row;
 9050
 9051        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
 9052        let anchor_end = snapshot
 9053            .buffer_snapshot
 9054            .anchor_after(Point::new(row, line_len));
 9055
 9056        let bp = self
 9057            .breakpoint_store
 9058            .as_ref()?
 9059            .read_with(cx, |breakpoint_store, cx| {
 9060                breakpoint_store
 9061                    .breakpoints(
 9062                        &buffer,
 9063                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
 9064                        &buffer_snapshot,
 9065                        cx,
 9066                    )
 9067                    .next()
 9068                    .and_then(|(anchor, bp)| {
 9069                        let breakpoint_row = buffer_snapshot
 9070                            .summary_for_anchor::<text::PointUtf16>(anchor)
 9071                            .row;
 9072
 9073                        if breakpoint_row == row {
 9074                            snapshot
 9075                                .buffer_snapshot
 9076                                .anchor_in_excerpt(enclosing_excerpt, *anchor)
 9077                                .map(|anchor| (anchor, bp.clone()))
 9078                        } else {
 9079                            None
 9080                        }
 9081                    })
 9082            });
 9083        bp
 9084    }
 9085
 9086    pub fn edit_log_breakpoint(
 9087        &mut self,
 9088        _: &EditLogBreakpoint,
 9089        window: &mut Window,
 9090        cx: &mut Context<Self>,
 9091    ) {
 9092        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9093            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
 9094                message: None,
 9095                state: BreakpointState::Enabled,
 9096                condition: None,
 9097                hit_condition: None,
 9098            });
 9099
 9100            self.add_edit_breakpoint_block(
 9101                anchor,
 9102                &breakpoint,
 9103                BreakpointPromptEditAction::Log,
 9104                window,
 9105                cx,
 9106            );
 9107        }
 9108    }
 9109
 9110    fn breakpoints_at_cursors(
 9111        &self,
 9112        window: &mut Window,
 9113        cx: &mut Context<Self>,
 9114    ) -> Vec<(Anchor, Option<Breakpoint>)> {
 9115        let snapshot = self.snapshot(window, cx);
 9116        let cursors = self
 9117            .selections
 9118            .disjoint_anchors()
 9119            .into_iter()
 9120            .map(|selection| {
 9121                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
 9122
 9123                let breakpoint_position = self
 9124                    .breakpoint_at_row(cursor_position.row, window, cx)
 9125                    .map(|bp| bp.0)
 9126                    .unwrap_or_else(|| {
 9127                        snapshot
 9128                            .display_snapshot
 9129                            .buffer_snapshot
 9130                            .anchor_after(Point::new(cursor_position.row, 0))
 9131                    });
 9132
 9133                let breakpoint = self
 9134                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9135                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
 9136
 9137                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
 9138            })
 9139            // 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.
 9140            .collect::<HashMap<Anchor, _>>();
 9141
 9142        cursors.into_iter().collect()
 9143    }
 9144
 9145    pub fn enable_breakpoint(
 9146        &mut self,
 9147        _: &crate::actions::EnableBreakpoint,
 9148        window: &mut Window,
 9149        cx: &mut Context<Self>,
 9150    ) {
 9151        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9152            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
 9153                continue;
 9154            };
 9155            self.edit_breakpoint_at_anchor(
 9156                anchor,
 9157                breakpoint,
 9158                BreakpointEditAction::InvertState,
 9159                cx,
 9160            );
 9161        }
 9162    }
 9163
 9164    pub fn disable_breakpoint(
 9165        &mut self,
 9166        _: &crate::actions::DisableBreakpoint,
 9167        window: &mut Window,
 9168        cx: &mut Context<Self>,
 9169    ) {
 9170        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9171            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
 9172                continue;
 9173            };
 9174            self.edit_breakpoint_at_anchor(
 9175                anchor,
 9176                breakpoint,
 9177                BreakpointEditAction::InvertState,
 9178                cx,
 9179            );
 9180        }
 9181    }
 9182
 9183    pub fn toggle_breakpoint(
 9184        &mut self,
 9185        _: &crate::actions::ToggleBreakpoint,
 9186        window: &mut Window,
 9187        cx: &mut Context<Self>,
 9188    ) {
 9189        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9190            if let Some(breakpoint) = breakpoint {
 9191                self.edit_breakpoint_at_anchor(
 9192                    anchor,
 9193                    breakpoint,
 9194                    BreakpointEditAction::Toggle,
 9195                    cx,
 9196                );
 9197            } else {
 9198                self.edit_breakpoint_at_anchor(
 9199                    anchor,
 9200                    Breakpoint::new_standard(),
 9201                    BreakpointEditAction::Toggle,
 9202                    cx,
 9203                );
 9204            }
 9205        }
 9206    }
 9207
 9208    pub fn edit_breakpoint_at_anchor(
 9209        &mut self,
 9210        breakpoint_position: Anchor,
 9211        breakpoint: Breakpoint,
 9212        edit_action: BreakpointEditAction,
 9213        cx: &mut Context<Self>,
 9214    ) {
 9215        let Some(breakpoint_store) = &self.breakpoint_store else {
 9216            return;
 9217        };
 9218
 9219        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
 9220            if breakpoint_position == Anchor::min() {
 9221                self.buffer()
 9222                    .read(cx)
 9223                    .excerpt_buffer_ids()
 9224                    .into_iter()
 9225                    .next()
 9226            } else {
 9227                None
 9228            }
 9229        }) else {
 9230            return;
 9231        };
 9232
 9233        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
 9234            return;
 9235        };
 9236
 9237        breakpoint_store.update(cx, |breakpoint_store, cx| {
 9238            breakpoint_store.toggle_breakpoint(
 9239                buffer,
 9240                (breakpoint_position.text_anchor, breakpoint),
 9241                edit_action,
 9242                cx,
 9243            );
 9244        });
 9245
 9246        cx.notify();
 9247    }
 9248
 9249    #[cfg(any(test, feature = "test-support"))]
 9250    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
 9251        self.breakpoint_store.clone()
 9252    }
 9253
 9254    pub fn prepare_restore_change(
 9255        &self,
 9256        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
 9257        hunk: &MultiBufferDiffHunk,
 9258        cx: &mut App,
 9259    ) -> Option<()> {
 9260        if hunk.is_created_file() {
 9261            return None;
 9262        }
 9263        let buffer = self.buffer.read(cx);
 9264        let diff = buffer.diff_for(hunk.buffer_id)?;
 9265        let buffer = buffer.buffer(hunk.buffer_id)?;
 9266        let buffer = buffer.read(cx);
 9267        let original_text = diff
 9268            .read(cx)
 9269            .base_text()
 9270            .as_rope()
 9271            .slice(hunk.diff_base_byte_range.clone());
 9272        let buffer_snapshot = buffer.snapshot();
 9273        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
 9274        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
 9275            probe
 9276                .0
 9277                .start
 9278                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
 9279                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
 9280        }) {
 9281            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
 9282            Some(())
 9283        } else {
 9284            None
 9285        }
 9286    }
 9287
 9288    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
 9289        self.manipulate_lines(window, cx, |lines| lines.reverse())
 9290    }
 9291
 9292    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
 9293        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
 9294    }
 9295
 9296    fn manipulate_lines<Fn>(
 9297        &mut self,
 9298        window: &mut Window,
 9299        cx: &mut Context<Self>,
 9300        mut callback: Fn,
 9301    ) where
 9302        Fn: FnMut(&mut Vec<&str>),
 9303    {
 9304        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9305
 9306        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9307        let buffer = self.buffer.read(cx).snapshot(cx);
 9308
 9309        let mut edits = Vec::new();
 9310
 9311        let selections = self.selections.all::<Point>(cx);
 9312        let mut selections = selections.iter().peekable();
 9313        let mut contiguous_row_selections = Vec::new();
 9314        let mut new_selections = Vec::new();
 9315        let mut added_lines = 0;
 9316        let mut removed_lines = 0;
 9317
 9318        while let Some(selection) = selections.next() {
 9319            let (start_row, end_row) = consume_contiguous_rows(
 9320                &mut contiguous_row_selections,
 9321                selection,
 9322                &display_map,
 9323                &mut selections,
 9324            );
 9325
 9326            let start_point = Point::new(start_row.0, 0);
 9327            let end_point = Point::new(
 9328                end_row.previous_row().0,
 9329                buffer.line_len(end_row.previous_row()),
 9330            );
 9331            let text = buffer
 9332                .text_for_range(start_point..end_point)
 9333                .collect::<String>();
 9334
 9335            let mut lines = text.split('\n').collect_vec();
 9336
 9337            let lines_before = lines.len();
 9338            callback(&mut lines);
 9339            let lines_after = lines.len();
 9340
 9341            edits.push((start_point..end_point, lines.join("\n")));
 9342
 9343            // Selections must change based on added and removed line count
 9344            let start_row =
 9345                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
 9346            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
 9347            new_selections.push(Selection {
 9348                id: selection.id,
 9349                start: start_row,
 9350                end: end_row,
 9351                goal: SelectionGoal::None,
 9352                reversed: selection.reversed,
 9353            });
 9354
 9355            if lines_after > lines_before {
 9356                added_lines += lines_after - lines_before;
 9357            } else if lines_before > lines_after {
 9358                removed_lines += lines_before - lines_after;
 9359            }
 9360        }
 9361
 9362        self.transact(window, cx, |this, window, cx| {
 9363            let buffer = this.buffer.update(cx, |buffer, cx| {
 9364                buffer.edit(edits, None, cx);
 9365                buffer.snapshot(cx)
 9366            });
 9367
 9368            // Recalculate offsets on newly edited buffer
 9369            let new_selections = new_selections
 9370                .iter()
 9371                .map(|s| {
 9372                    let start_point = Point::new(s.start.0, 0);
 9373                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
 9374                    Selection {
 9375                        id: s.id,
 9376                        start: buffer.point_to_offset(start_point),
 9377                        end: buffer.point_to_offset(end_point),
 9378                        goal: s.goal,
 9379                        reversed: s.reversed,
 9380                    }
 9381                })
 9382                .collect();
 9383
 9384            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9385                s.select(new_selections);
 9386            });
 9387
 9388            this.request_autoscroll(Autoscroll::fit(), cx);
 9389        });
 9390    }
 9391
 9392    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
 9393        self.manipulate_text(window, cx, |text| {
 9394            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
 9395            if has_upper_case_characters {
 9396                text.to_lowercase()
 9397            } else {
 9398                text.to_uppercase()
 9399            }
 9400        })
 9401    }
 9402
 9403    pub fn convert_to_upper_case(
 9404        &mut self,
 9405        _: &ConvertToUpperCase,
 9406        window: &mut Window,
 9407        cx: &mut Context<Self>,
 9408    ) {
 9409        self.manipulate_text(window, cx, |text| text.to_uppercase())
 9410    }
 9411
 9412    pub fn convert_to_lower_case(
 9413        &mut self,
 9414        _: &ConvertToLowerCase,
 9415        window: &mut Window,
 9416        cx: &mut Context<Self>,
 9417    ) {
 9418        self.manipulate_text(window, cx, |text| text.to_lowercase())
 9419    }
 9420
 9421    pub fn convert_to_title_case(
 9422        &mut self,
 9423        _: &ConvertToTitleCase,
 9424        window: &mut Window,
 9425        cx: &mut Context<Self>,
 9426    ) {
 9427        self.manipulate_text(window, cx, |text| {
 9428            text.split('\n')
 9429                .map(|line| line.to_case(Case::Title))
 9430                .join("\n")
 9431        })
 9432    }
 9433
 9434    pub fn convert_to_snake_case(
 9435        &mut self,
 9436        _: &ConvertToSnakeCase,
 9437        window: &mut Window,
 9438        cx: &mut Context<Self>,
 9439    ) {
 9440        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
 9441    }
 9442
 9443    pub fn convert_to_kebab_case(
 9444        &mut self,
 9445        _: &ConvertToKebabCase,
 9446        window: &mut Window,
 9447        cx: &mut Context<Self>,
 9448    ) {
 9449        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
 9450    }
 9451
 9452    pub fn convert_to_upper_camel_case(
 9453        &mut self,
 9454        _: &ConvertToUpperCamelCase,
 9455        window: &mut Window,
 9456        cx: &mut Context<Self>,
 9457    ) {
 9458        self.manipulate_text(window, cx, |text| {
 9459            text.split('\n')
 9460                .map(|line| line.to_case(Case::UpperCamel))
 9461                .join("\n")
 9462        })
 9463    }
 9464
 9465    pub fn convert_to_lower_camel_case(
 9466        &mut self,
 9467        _: &ConvertToLowerCamelCase,
 9468        window: &mut Window,
 9469        cx: &mut Context<Self>,
 9470    ) {
 9471        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
 9472    }
 9473
 9474    pub fn convert_to_opposite_case(
 9475        &mut self,
 9476        _: &ConvertToOppositeCase,
 9477        window: &mut Window,
 9478        cx: &mut Context<Self>,
 9479    ) {
 9480        self.manipulate_text(window, cx, |text| {
 9481            text.chars()
 9482                .fold(String::with_capacity(text.len()), |mut t, c| {
 9483                    if c.is_uppercase() {
 9484                        t.extend(c.to_lowercase());
 9485                    } else {
 9486                        t.extend(c.to_uppercase());
 9487                    }
 9488                    t
 9489                })
 9490        })
 9491    }
 9492
 9493    pub fn convert_to_rot13(
 9494        &mut self,
 9495        _: &ConvertToRot13,
 9496        window: &mut Window,
 9497        cx: &mut Context<Self>,
 9498    ) {
 9499        self.manipulate_text(window, cx, |text| {
 9500            text.chars()
 9501                .map(|c| match c {
 9502                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
 9503                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
 9504                    _ => c,
 9505                })
 9506                .collect()
 9507        })
 9508    }
 9509
 9510    pub fn convert_to_rot47(
 9511        &mut self,
 9512        _: &ConvertToRot47,
 9513        window: &mut Window,
 9514        cx: &mut Context<Self>,
 9515    ) {
 9516        self.manipulate_text(window, cx, |text| {
 9517            text.chars()
 9518                .map(|c| {
 9519                    let code_point = c as u32;
 9520                    if code_point >= 33 && code_point <= 126 {
 9521                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
 9522                    }
 9523                    c
 9524                })
 9525                .collect()
 9526        })
 9527    }
 9528
 9529    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
 9530    where
 9531        Fn: FnMut(&str) -> String,
 9532    {
 9533        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9534        let buffer = self.buffer.read(cx).snapshot(cx);
 9535
 9536        let mut new_selections = Vec::new();
 9537        let mut edits = Vec::new();
 9538        let mut selection_adjustment = 0i32;
 9539
 9540        for selection in self.selections.all::<usize>(cx) {
 9541            let selection_is_empty = selection.is_empty();
 9542
 9543            let (start, end) = if selection_is_empty {
 9544                let word_range = movement::surrounding_word(
 9545                    &display_map,
 9546                    selection.start.to_display_point(&display_map),
 9547                );
 9548                let start = word_range.start.to_offset(&display_map, Bias::Left);
 9549                let end = word_range.end.to_offset(&display_map, Bias::Left);
 9550                (start, end)
 9551            } else {
 9552                (selection.start, selection.end)
 9553            };
 9554
 9555            let text = buffer.text_for_range(start..end).collect::<String>();
 9556            let old_length = text.len() as i32;
 9557            let text = callback(&text);
 9558
 9559            new_selections.push(Selection {
 9560                start: (start as i32 - selection_adjustment) as usize,
 9561                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
 9562                goal: SelectionGoal::None,
 9563                ..selection
 9564            });
 9565
 9566            selection_adjustment += old_length - text.len() as i32;
 9567
 9568            edits.push((start..end, text));
 9569        }
 9570
 9571        self.transact(window, cx, |this, window, cx| {
 9572            this.buffer.update(cx, |buffer, cx| {
 9573                buffer.edit(edits, None, cx);
 9574            });
 9575
 9576            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9577                s.select(new_selections);
 9578            });
 9579
 9580            this.request_autoscroll(Autoscroll::fit(), cx);
 9581        });
 9582    }
 9583
 9584    pub fn duplicate(
 9585        &mut self,
 9586        upwards: bool,
 9587        whole_lines: bool,
 9588        window: &mut Window,
 9589        cx: &mut Context<Self>,
 9590    ) {
 9591        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9592
 9593        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9594        let buffer = &display_map.buffer_snapshot;
 9595        let selections = self.selections.all::<Point>(cx);
 9596
 9597        let mut edits = Vec::new();
 9598        let mut selections_iter = selections.iter().peekable();
 9599        while let Some(selection) = selections_iter.next() {
 9600            let mut rows = selection.spanned_rows(false, &display_map);
 9601            // duplicate line-wise
 9602            if whole_lines || selection.start == selection.end {
 9603                // Avoid duplicating the same lines twice.
 9604                while let Some(next_selection) = selections_iter.peek() {
 9605                    let next_rows = next_selection.spanned_rows(false, &display_map);
 9606                    if next_rows.start < rows.end {
 9607                        rows.end = next_rows.end;
 9608                        selections_iter.next().unwrap();
 9609                    } else {
 9610                        break;
 9611                    }
 9612                }
 9613
 9614                // Copy the text from the selected row region and splice it either at the start
 9615                // or end of the region.
 9616                let start = Point::new(rows.start.0, 0);
 9617                let end = Point::new(
 9618                    rows.end.previous_row().0,
 9619                    buffer.line_len(rows.end.previous_row()),
 9620                );
 9621                let text = buffer
 9622                    .text_for_range(start..end)
 9623                    .chain(Some("\n"))
 9624                    .collect::<String>();
 9625                let insert_location = if upwards {
 9626                    Point::new(rows.end.0, 0)
 9627                } else {
 9628                    start
 9629                };
 9630                edits.push((insert_location..insert_location, text));
 9631            } else {
 9632                // duplicate character-wise
 9633                let start = selection.start;
 9634                let end = selection.end;
 9635                let text = buffer.text_for_range(start..end).collect::<String>();
 9636                edits.push((selection.end..selection.end, text));
 9637            }
 9638        }
 9639
 9640        self.transact(window, cx, |this, _, cx| {
 9641            this.buffer.update(cx, |buffer, cx| {
 9642                buffer.edit(edits, None, cx);
 9643            });
 9644
 9645            this.request_autoscroll(Autoscroll::fit(), cx);
 9646        });
 9647    }
 9648
 9649    pub fn duplicate_line_up(
 9650        &mut self,
 9651        _: &DuplicateLineUp,
 9652        window: &mut Window,
 9653        cx: &mut Context<Self>,
 9654    ) {
 9655        self.duplicate(true, true, window, cx);
 9656    }
 9657
 9658    pub fn duplicate_line_down(
 9659        &mut self,
 9660        _: &DuplicateLineDown,
 9661        window: &mut Window,
 9662        cx: &mut Context<Self>,
 9663    ) {
 9664        self.duplicate(false, true, window, cx);
 9665    }
 9666
 9667    pub fn duplicate_selection(
 9668        &mut self,
 9669        _: &DuplicateSelection,
 9670        window: &mut Window,
 9671        cx: &mut Context<Self>,
 9672    ) {
 9673        self.duplicate(false, false, window, cx);
 9674    }
 9675
 9676    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
 9677        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9678
 9679        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9680        let buffer = self.buffer.read(cx).snapshot(cx);
 9681
 9682        let mut edits = Vec::new();
 9683        let mut unfold_ranges = Vec::new();
 9684        let mut refold_creases = Vec::new();
 9685
 9686        let selections = self.selections.all::<Point>(cx);
 9687        let mut selections = selections.iter().peekable();
 9688        let mut contiguous_row_selections = Vec::new();
 9689        let mut new_selections = Vec::new();
 9690
 9691        while let Some(selection) = selections.next() {
 9692            // Find all the selections that span a contiguous row range
 9693            let (start_row, end_row) = consume_contiguous_rows(
 9694                &mut contiguous_row_selections,
 9695                selection,
 9696                &display_map,
 9697                &mut selections,
 9698            );
 9699
 9700            // Move the text spanned by the row range to be before the line preceding the row range
 9701            if start_row.0 > 0 {
 9702                let range_to_move = Point::new(
 9703                    start_row.previous_row().0,
 9704                    buffer.line_len(start_row.previous_row()),
 9705                )
 9706                    ..Point::new(
 9707                        end_row.previous_row().0,
 9708                        buffer.line_len(end_row.previous_row()),
 9709                    );
 9710                let insertion_point = display_map
 9711                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
 9712                    .0;
 9713
 9714                // Don't move lines across excerpts
 9715                if buffer
 9716                    .excerpt_containing(insertion_point..range_to_move.end)
 9717                    .is_some()
 9718                {
 9719                    let text = buffer
 9720                        .text_for_range(range_to_move.clone())
 9721                        .flat_map(|s| s.chars())
 9722                        .skip(1)
 9723                        .chain(['\n'])
 9724                        .collect::<String>();
 9725
 9726                    edits.push((
 9727                        buffer.anchor_after(range_to_move.start)
 9728                            ..buffer.anchor_before(range_to_move.end),
 9729                        String::new(),
 9730                    ));
 9731                    let insertion_anchor = buffer.anchor_after(insertion_point);
 9732                    edits.push((insertion_anchor..insertion_anchor, text));
 9733
 9734                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
 9735
 9736                    // Move selections up
 9737                    new_selections.extend(contiguous_row_selections.drain(..).map(
 9738                        |mut selection| {
 9739                            selection.start.row -= row_delta;
 9740                            selection.end.row -= row_delta;
 9741                            selection
 9742                        },
 9743                    ));
 9744
 9745                    // Move folds up
 9746                    unfold_ranges.push(range_to_move.clone());
 9747                    for fold in display_map.folds_in_range(
 9748                        buffer.anchor_before(range_to_move.start)
 9749                            ..buffer.anchor_after(range_to_move.end),
 9750                    ) {
 9751                        let mut start = fold.range.start.to_point(&buffer);
 9752                        let mut end = fold.range.end.to_point(&buffer);
 9753                        start.row -= row_delta;
 9754                        end.row -= row_delta;
 9755                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
 9756                    }
 9757                }
 9758            }
 9759
 9760            // If we didn't move line(s), preserve the existing selections
 9761            new_selections.append(&mut contiguous_row_selections);
 9762        }
 9763
 9764        self.transact(window, cx, |this, window, cx| {
 9765            this.unfold_ranges(&unfold_ranges, true, true, cx);
 9766            this.buffer.update(cx, |buffer, cx| {
 9767                for (range, text) in edits {
 9768                    buffer.edit([(range, text)], None, cx);
 9769                }
 9770            });
 9771            this.fold_creases(refold_creases, true, window, cx);
 9772            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9773                s.select(new_selections);
 9774            })
 9775        });
 9776    }
 9777
 9778    pub fn move_line_down(
 9779        &mut self,
 9780        _: &MoveLineDown,
 9781        window: &mut Window,
 9782        cx: &mut Context<Self>,
 9783    ) {
 9784        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9785
 9786        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9787        let buffer = self.buffer.read(cx).snapshot(cx);
 9788
 9789        let mut edits = Vec::new();
 9790        let mut unfold_ranges = Vec::new();
 9791        let mut refold_creases = Vec::new();
 9792
 9793        let selections = self.selections.all::<Point>(cx);
 9794        let mut selections = selections.iter().peekable();
 9795        let mut contiguous_row_selections = Vec::new();
 9796        let mut new_selections = Vec::new();
 9797
 9798        while let Some(selection) = selections.next() {
 9799            // Find all the selections that span a contiguous row range
 9800            let (start_row, end_row) = consume_contiguous_rows(
 9801                &mut contiguous_row_selections,
 9802                selection,
 9803                &display_map,
 9804                &mut selections,
 9805            );
 9806
 9807            // Move the text spanned by the row range to be after the last line of the row range
 9808            if end_row.0 <= buffer.max_point().row {
 9809                let range_to_move =
 9810                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
 9811                let insertion_point = display_map
 9812                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
 9813                    .0;
 9814
 9815                // Don't move lines across excerpt boundaries
 9816                if buffer
 9817                    .excerpt_containing(range_to_move.start..insertion_point)
 9818                    .is_some()
 9819                {
 9820                    let mut text = String::from("\n");
 9821                    text.extend(buffer.text_for_range(range_to_move.clone()));
 9822                    text.pop(); // Drop trailing newline
 9823                    edits.push((
 9824                        buffer.anchor_after(range_to_move.start)
 9825                            ..buffer.anchor_before(range_to_move.end),
 9826                        String::new(),
 9827                    ));
 9828                    let insertion_anchor = buffer.anchor_after(insertion_point);
 9829                    edits.push((insertion_anchor..insertion_anchor, text));
 9830
 9831                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
 9832
 9833                    // Move selections down
 9834                    new_selections.extend(contiguous_row_selections.drain(..).map(
 9835                        |mut selection| {
 9836                            selection.start.row += row_delta;
 9837                            selection.end.row += row_delta;
 9838                            selection
 9839                        },
 9840                    ));
 9841
 9842                    // Move folds down
 9843                    unfold_ranges.push(range_to_move.clone());
 9844                    for fold in display_map.folds_in_range(
 9845                        buffer.anchor_before(range_to_move.start)
 9846                            ..buffer.anchor_after(range_to_move.end),
 9847                    ) {
 9848                        let mut start = fold.range.start.to_point(&buffer);
 9849                        let mut end = fold.range.end.to_point(&buffer);
 9850                        start.row += row_delta;
 9851                        end.row += row_delta;
 9852                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
 9853                    }
 9854                }
 9855            }
 9856
 9857            // If we didn't move line(s), preserve the existing selections
 9858            new_selections.append(&mut contiguous_row_selections);
 9859        }
 9860
 9861        self.transact(window, cx, |this, window, cx| {
 9862            this.unfold_ranges(&unfold_ranges, true, true, cx);
 9863            this.buffer.update(cx, |buffer, cx| {
 9864                for (range, text) in edits {
 9865                    buffer.edit([(range, text)], None, cx);
 9866                }
 9867            });
 9868            this.fold_creases(refold_creases, true, window, cx);
 9869            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9870                s.select(new_selections)
 9871            });
 9872        });
 9873    }
 9874
 9875    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
 9876        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9877        let text_layout_details = &self.text_layout_details(window);
 9878        self.transact(window, cx, |this, window, cx| {
 9879            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9880                let mut edits: Vec<(Range<usize>, String)> = Default::default();
 9881                s.move_with(|display_map, selection| {
 9882                    if !selection.is_empty() {
 9883                        return;
 9884                    }
 9885
 9886                    let mut head = selection.head();
 9887                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
 9888                    if head.column() == display_map.line_len(head.row()) {
 9889                        transpose_offset = display_map
 9890                            .buffer_snapshot
 9891                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
 9892                    }
 9893
 9894                    if transpose_offset == 0 {
 9895                        return;
 9896                    }
 9897
 9898                    *head.column_mut() += 1;
 9899                    head = display_map.clip_point(head, Bias::Right);
 9900                    let goal = SelectionGoal::HorizontalPosition(
 9901                        display_map
 9902                            .x_for_display_point(head, text_layout_details)
 9903                            .into(),
 9904                    );
 9905                    selection.collapse_to(head, goal);
 9906
 9907                    let transpose_start = display_map
 9908                        .buffer_snapshot
 9909                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
 9910                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
 9911                        let transpose_end = display_map
 9912                            .buffer_snapshot
 9913                            .clip_offset(transpose_offset + 1, Bias::Right);
 9914                        if let Some(ch) =
 9915                            display_map.buffer_snapshot.chars_at(transpose_start).next()
 9916                        {
 9917                            edits.push((transpose_start..transpose_offset, String::new()));
 9918                            edits.push((transpose_end..transpose_end, ch.to_string()));
 9919                        }
 9920                    }
 9921                });
 9922                edits
 9923            });
 9924            this.buffer
 9925                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 9926            let selections = this.selections.all::<usize>(cx);
 9927            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9928                s.select(selections);
 9929            });
 9930        });
 9931    }
 9932
 9933    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
 9934        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9935        self.rewrap_impl(RewrapOptions::default(), cx)
 9936    }
 9937
 9938    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
 9939        let buffer = self.buffer.read(cx).snapshot(cx);
 9940        let selections = self.selections.all::<Point>(cx);
 9941        let mut selections = selections.iter().peekable();
 9942
 9943        let mut edits = Vec::new();
 9944        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
 9945
 9946        while let Some(selection) = selections.next() {
 9947            let mut start_row = selection.start.row;
 9948            let mut end_row = selection.end.row;
 9949
 9950            // Skip selections that overlap with a range that has already been rewrapped.
 9951            let selection_range = start_row..end_row;
 9952            if rewrapped_row_ranges
 9953                .iter()
 9954                .any(|range| range.overlaps(&selection_range))
 9955            {
 9956                continue;
 9957            }
 9958
 9959            let tab_size = buffer.language_settings_at(selection.head(), cx).tab_size;
 9960
 9961            // Since not all lines in the selection may be at the same indent
 9962            // level, choose the indent size that is the most common between all
 9963            // of the lines.
 9964            //
 9965            // If there is a tie, we use the deepest indent.
 9966            let (indent_size, indent_end) = {
 9967                let mut indent_size_occurrences = HashMap::default();
 9968                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
 9969
 9970                for row in start_row..=end_row {
 9971                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
 9972                    rows_by_indent_size.entry(indent).or_default().push(row);
 9973                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
 9974                }
 9975
 9976                let indent_size = indent_size_occurrences
 9977                    .into_iter()
 9978                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
 9979                    .map(|(indent, _)| indent)
 9980                    .unwrap_or_default();
 9981                let row = rows_by_indent_size[&indent_size][0];
 9982                let indent_end = Point::new(row, indent_size.len);
 9983
 9984                (indent_size, indent_end)
 9985            };
 9986
 9987            let mut line_prefix = indent_size.chars().collect::<String>();
 9988
 9989            let mut inside_comment = false;
 9990            if let Some(comment_prefix) =
 9991                buffer
 9992                    .language_scope_at(selection.head())
 9993                    .and_then(|language| {
 9994                        language
 9995                            .line_comment_prefixes()
 9996                            .iter()
 9997                            .find(|prefix| buffer.contains_str_at(indent_end, prefix))
 9998                            .cloned()
 9999                    })
10000            {
10001                line_prefix.push_str(&comment_prefix);
10002                inside_comment = true;
10003            }
10004
10005            let language_settings = buffer.language_settings_at(selection.head(), cx);
10006            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
10007                RewrapBehavior::InComments => inside_comment,
10008                RewrapBehavior::InSelections => !selection.is_empty(),
10009                RewrapBehavior::Anywhere => true,
10010            };
10011
10012            let should_rewrap = options.override_language_settings
10013                || allow_rewrap_based_on_language
10014                || self.hard_wrap.is_some();
10015            if !should_rewrap {
10016                continue;
10017            }
10018
10019            if selection.is_empty() {
10020                'expand_upwards: while start_row > 0 {
10021                    let prev_row = start_row - 1;
10022                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
10023                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
10024                    {
10025                        start_row = prev_row;
10026                    } else {
10027                        break 'expand_upwards;
10028                    }
10029                }
10030
10031                'expand_downwards: while end_row < buffer.max_point().row {
10032                    let next_row = end_row + 1;
10033                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
10034                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
10035                    {
10036                        end_row = next_row;
10037                    } else {
10038                        break 'expand_downwards;
10039                    }
10040                }
10041            }
10042
10043            let start = Point::new(start_row, 0);
10044            let start_offset = start.to_offset(&buffer);
10045            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
10046            let selection_text = buffer.text_for_range(start..end).collect::<String>();
10047            let Some(lines_without_prefixes) = selection_text
10048                .lines()
10049                .map(|line| {
10050                    line.strip_prefix(&line_prefix)
10051                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
10052                        .ok_or_else(|| {
10053                            anyhow!("line did not start with prefix {line_prefix:?}: {line:?}")
10054                        })
10055                })
10056                .collect::<Result<Vec<_>, _>>()
10057                .log_err()
10058            else {
10059                continue;
10060            };
10061
10062            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
10063                buffer
10064                    .language_settings_at(Point::new(start_row, 0), cx)
10065                    .preferred_line_length as usize
10066            });
10067            let wrapped_text = wrap_with_prefix(
10068                line_prefix,
10069                lines_without_prefixes.join("\n"),
10070                wrap_column,
10071                tab_size,
10072                options.preserve_existing_whitespace,
10073            );
10074
10075            // TODO: should always use char-based diff while still supporting cursor behavior that
10076            // matches vim.
10077            let mut diff_options = DiffOptions::default();
10078            if options.override_language_settings {
10079                diff_options.max_word_diff_len = 0;
10080                diff_options.max_word_diff_line_count = 0;
10081            } else {
10082                diff_options.max_word_diff_len = usize::MAX;
10083                diff_options.max_word_diff_line_count = usize::MAX;
10084            }
10085
10086            for (old_range, new_text) in
10087                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
10088            {
10089                let edit_start = buffer.anchor_after(start_offset + old_range.start);
10090                let edit_end = buffer.anchor_after(start_offset + old_range.end);
10091                edits.push((edit_start..edit_end, new_text));
10092            }
10093
10094            rewrapped_row_ranges.push(start_row..=end_row);
10095        }
10096
10097        self.buffer
10098            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10099    }
10100
10101    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
10102        let mut text = String::new();
10103        let buffer = self.buffer.read(cx).snapshot(cx);
10104        let mut selections = self.selections.all::<Point>(cx);
10105        let mut clipboard_selections = Vec::with_capacity(selections.len());
10106        {
10107            let max_point = buffer.max_point();
10108            let mut is_first = true;
10109            for selection in &mut selections {
10110                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10111                if is_entire_line {
10112                    selection.start = Point::new(selection.start.row, 0);
10113                    if !selection.is_empty() && selection.end.column == 0 {
10114                        selection.end = cmp::min(max_point, selection.end);
10115                    } else {
10116                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
10117                    }
10118                    selection.goal = SelectionGoal::None;
10119                }
10120                if is_first {
10121                    is_first = false;
10122                } else {
10123                    text += "\n";
10124                }
10125                let mut len = 0;
10126                for chunk in buffer.text_for_range(selection.start..selection.end) {
10127                    text.push_str(chunk);
10128                    len += chunk.len();
10129                }
10130                clipboard_selections.push(ClipboardSelection {
10131                    len,
10132                    is_entire_line,
10133                    first_line_indent: buffer
10134                        .indent_size_for_line(MultiBufferRow(selection.start.row))
10135                        .len,
10136                });
10137            }
10138        }
10139
10140        self.transact(window, cx, |this, window, cx| {
10141            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10142                s.select(selections);
10143            });
10144            this.insert("", window, cx);
10145        });
10146        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
10147    }
10148
10149    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
10150        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10151        let item = self.cut_common(window, cx);
10152        cx.write_to_clipboard(item);
10153    }
10154
10155    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
10156        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10157        self.change_selections(None, window, cx, |s| {
10158            s.move_with(|snapshot, sel| {
10159                if sel.is_empty() {
10160                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
10161                }
10162            });
10163        });
10164        let item = self.cut_common(window, cx);
10165        cx.set_global(KillRing(item))
10166    }
10167
10168    pub fn kill_ring_yank(
10169        &mut self,
10170        _: &KillRingYank,
10171        window: &mut Window,
10172        cx: &mut Context<Self>,
10173    ) {
10174        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10175        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
10176            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
10177                (kill_ring.text().to_string(), kill_ring.metadata_json())
10178            } else {
10179                return;
10180            }
10181        } else {
10182            return;
10183        };
10184        self.do_paste(&text, metadata, false, window, cx);
10185    }
10186
10187    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
10188        self.do_copy(true, cx);
10189    }
10190
10191    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
10192        self.do_copy(false, cx);
10193    }
10194
10195    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
10196        let selections = self.selections.all::<Point>(cx);
10197        let buffer = self.buffer.read(cx).read(cx);
10198        let mut text = String::new();
10199
10200        let mut clipboard_selections = Vec::with_capacity(selections.len());
10201        {
10202            let max_point = buffer.max_point();
10203            let mut is_first = true;
10204            for selection in &selections {
10205                let mut start = selection.start;
10206                let mut end = selection.end;
10207                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10208                if is_entire_line {
10209                    start = Point::new(start.row, 0);
10210                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
10211                }
10212
10213                let mut trimmed_selections = Vec::new();
10214                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
10215                    let row = MultiBufferRow(start.row);
10216                    let first_indent = buffer.indent_size_for_line(row);
10217                    if first_indent.len == 0 || start.column > first_indent.len {
10218                        trimmed_selections.push(start..end);
10219                    } else {
10220                        trimmed_selections.push(
10221                            Point::new(row.0, first_indent.len)
10222                                ..Point::new(row.0, buffer.line_len(row)),
10223                        );
10224                        for row in start.row + 1..=end.row {
10225                            let mut line_len = buffer.line_len(MultiBufferRow(row));
10226                            if row == end.row {
10227                                line_len = end.column;
10228                            }
10229                            if line_len == 0 {
10230                                trimmed_selections
10231                                    .push(Point::new(row, 0)..Point::new(row, line_len));
10232                                continue;
10233                            }
10234                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
10235                            if row_indent_size.len >= first_indent.len {
10236                                trimmed_selections.push(
10237                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
10238                                );
10239                            } else {
10240                                trimmed_selections.clear();
10241                                trimmed_selections.push(start..end);
10242                                break;
10243                            }
10244                        }
10245                    }
10246                } else {
10247                    trimmed_selections.push(start..end);
10248                }
10249
10250                for trimmed_range in trimmed_selections {
10251                    if is_first {
10252                        is_first = false;
10253                    } else {
10254                        text += "\n";
10255                    }
10256                    let mut len = 0;
10257                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
10258                        text.push_str(chunk);
10259                        len += chunk.len();
10260                    }
10261                    clipboard_selections.push(ClipboardSelection {
10262                        len,
10263                        is_entire_line,
10264                        first_line_indent: buffer
10265                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
10266                            .len,
10267                    });
10268                }
10269            }
10270        }
10271
10272        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
10273            text,
10274            clipboard_selections,
10275        ));
10276    }
10277
10278    pub fn do_paste(
10279        &mut self,
10280        text: &String,
10281        clipboard_selections: Option<Vec<ClipboardSelection>>,
10282        handle_entire_lines: bool,
10283        window: &mut Window,
10284        cx: &mut Context<Self>,
10285    ) {
10286        if self.read_only(cx) {
10287            return;
10288        }
10289
10290        let clipboard_text = Cow::Borrowed(text);
10291
10292        self.transact(window, cx, |this, window, cx| {
10293            if let Some(mut clipboard_selections) = clipboard_selections {
10294                let old_selections = this.selections.all::<usize>(cx);
10295                let all_selections_were_entire_line =
10296                    clipboard_selections.iter().all(|s| s.is_entire_line);
10297                let first_selection_indent_column =
10298                    clipboard_selections.first().map(|s| s.first_line_indent);
10299                if clipboard_selections.len() != old_selections.len() {
10300                    clipboard_selections.drain(..);
10301                }
10302                let cursor_offset = this.selections.last::<usize>(cx).head();
10303                let mut auto_indent_on_paste = true;
10304
10305                this.buffer.update(cx, |buffer, cx| {
10306                    let snapshot = buffer.read(cx);
10307                    auto_indent_on_paste = snapshot
10308                        .language_settings_at(cursor_offset, cx)
10309                        .auto_indent_on_paste;
10310
10311                    let mut start_offset = 0;
10312                    let mut edits = Vec::new();
10313                    let mut original_indent_columns = Vec::new();
10314                    for (ix, selection) in old_selections.iter().enumerate() {
10315                        let to_insert;
10316                        let entire_line;
10317                        let original_indent_column;
10318                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
10319                            let end_offset = start_offset + clipboard_selection.len;
10320                            to_insert = &clipboard_text[start_offset..end_offset];
10321                            entire_line = clipboard_selection.is_entire_line;
10322                            start_offset = end_offset + 1;
10323                            original_indent_column = Some(clipboard_selection.first_line_indent);
10324                        } else {
10325                            to_insert = clipboard_text.as_str();
10326                            entire_line = all_selections_were_entire_line;
10327                            original_indent_column = first_selection_indent_column
10328                        }
10329
10330                        // If the corresponding selection was empty when this slice of the
10331                        // clipboard text was written, then the entire line containing the
10332                        // selection was copied. If this selection is also currently empty,
10333                        // then paste the line before the current line of the buffer.
10334                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
10335                            let column = selection.start.to_point(&snapshot).column as usize;
10336                            let line_start = selection.start - column;
10337                            line_start..line_start
10338                        } else {
10339                            selection.range()
10340                        };
10341
10342                        edits.push((range, to_insert));
10343                        original_indent_columns.push(original_indent_column);
10344                    }
10345                    drop(snapshot);
10346
10347                    buffer.edit(
10348                        edits,
10349                        if auto_indent_on_paste {
10350                            Some(AutoindentMode::Block {
10351                                original_indent_columns,
10352                            })
10353                        } else {
10354                            None
10355                        },
10356                        cx,
10357                    );
10358                });
10359
10360                let selections = this.selections.all::<usize>(cx);
10361                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10362                    s.select(selections)
10363                });
10364            } else {
10365                this.insert(&clipboard_text, window, cx);
10366            }
10367        });
10368    }
10369
10370    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
10371        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10372        if let Some(item) = cx.read_from_clipboard() {
10373            let entries = item.entries();
10374
10375            match entries.first() {
10376                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
10377                // of all the pasted entries.
10378                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
10379                    .do_paste(
10380                        clipboard_string.text(),
10381                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
10382                        true,
10383                        window,
10384                        cx,
10385                    ),
10386                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
10387            }
10388        }
10389    }
10390
10391    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
10392        if self.read_only(cx) {
10393            return;
10394        }
10395
10396        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10397
10398        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
10399            if let Some((selections, _)) =
10400                self.selection_history.transaction(transaction_id).cloned()
10401            {
10402                self.change_selections(None, window, cx, |s| {
10403                    s.select_anchors(selections.to_vec());
10404                });
10405            } else {
10406                log::error!(
10407                    "No entry in selection_history found for undo. \
10408                     This may correspond to a bug where undo does not update the selection. \
10409                     If this is occurring, please add details to \
10410                     https://github.com/zed-industries/zed/issues/22692"
10411                );
10412            }
10413            self.request_autoscroll(Autoscroll::fit(), cx);
10414            self.unmark_text(window, cx);
10415            self.refresh_inline_completion(true, false, window, cx);
10416            cx.emit(EditorEvent::Edited { transaction_id });
10417            cx.emit(EditorEvent::TransactionUndone { transaction_id });
10418        }
10419    }
10420
10421    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
10422        if self.read_only(cx) {
10423            return;
10424        }
10425
10426        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10427
10428        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
10429            if let Some((_, Some(selections))) =
10430                self.selection_history.transaction(transaction_id).cloned()
10431            {
10432                self.change_selections(None, window, cx, |s| {
10433                    s.select_anchors(selections.to_vec());
10434                });
10435            } else {
10436                log::error!(
10437                    "No entry in selection_history found for redo. \
10438                     This may correspond to a bug where undo does not update the selection. \
10439                     If this is occurring, please add details to \
10440                     https://github.com/zed-industries/zed/issues/22692"
10441                );
10442            }
10443            self.request_autoscroll(Autoscroll::fit(), cx);
10444            self.unmark_text(window, cx);
10445            self.refresh_inline_completion(true, false, window, cx);
10446            cx.emit(EditorEvent::Edited { transaction_id });
10447        }
10448    }
10449
10450    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
10451        self.buffer
10452            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
10453    }
10454
10455    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
10456        self.buffer
10457            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
10458    }
10459
10460    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
10461        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10462        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10463            s.move_with(|map, selection| {
10464                let cursor = if selection.is_empty() {
10465                    movement::left(map, selection.start)
10466                } else {
10467                    selection.start
10468                };
10469                selection.collapse_to(cursor, SelectionGoal::None);
10470            });
10471        })
10472    }
10473
10474    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
10475        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10476        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10477            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
10478        })
10479    }
10480
10481    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
10482        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10483        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10484            s.move_with(|map, selection| {
10485                let cursor = if selection.is_empty() {
10486                    movement::right(map, selection.end)
10487                } else {
10488                    selection.end
10489                };
10490                selection.collapse_to(cursor, SelectionGoal::None)
10491            });
10492        })
10493    }
10494
10495    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
10496        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10497        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10498            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
10499        })
10500    }
10501
10502    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
10503        if self.take_rename(true, window, cx).is_some() {
10504            return;
10505        }
10506
10507        if matches!(self.mode, EditorMode::SingleLine { .. }) {
10508            cx.propagate();
10509            return;
10510        }
10511
10512        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10513
10514        let text_layout_details = &self.text_layout_details(window);
10515        let selection_count = self.selections.count();
10516        let first_selection = self.selections.first_anchor();
10517
10518        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10519            s.move_with(|map, selection| {
10520                if !selection.is_empty() {
10521                    selection.goal = SelectionGoal::None;
10522                }
10523                let (cursor, goal) = movement::up(
10524                    map,
10525                    selection.start,
10526                    selection.goal,
10527                    false,
10528                    text_layout_details,
10529                );
10530                selection.collapse_to(cursor, goal);
10531            });
10532        });
10533
10534        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
10535        {
10536            cx.propagate();
10537        }
10538    }
10539
10540    pub fn move_up_by_lines(
10541        &mut self,
10542        action: &MoveUpByLines,
10543        window: &mut Window,
10544        cx: &mut Context<Self>,
10545    ) {
10546        if self.take_rename(true, window, cx).is_some() {
10547            return;
10548        }
10549
10550        if matches!(self.mode, EditorMode::SingleLine { .. }) {
10551            cx.propagate();
10552            return;
10553        }
10554
10555        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10556
10557        let text_layout_details = &self.text_layout_details(window);
10558
10559        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10560            s.move_with(|map, selection| {
10561                if !selection.is_empty() {
10562                    selection.goal = SelectionGoal::None;
10563                }
10564                let (cursor, goal) = movement::up_by_rows(
10565                    map,
10566                    selection.start,
10567                    action.lines,
10568                    selection.goal,
10569                    false,
10570                    text_layout_details,
10571                );
10572                selection.collapse_to(cursor, goal);
10573            });
10574        })
10575    }
10576
10577    pub fn move_down_by_lines(
10578        &mut self,
10579        action: &MoveDownByLines,
10580        window: &mut Window,
10581        cx: &mut Context<Self>,
10582    ) {
10583        if self.take_rename(true, window, cx).is_some() {
10584            return;
10585        }
10586
10587        if matches!(self.mode, EditorMode::SingleLine { .. }) {
10588            cx.propagate();
10589            return;
10590        }
10591
10592        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10593
10594        let text_layout_details = &self.text_layout_details(window);
10595
10596        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10597            s.move_with(|map, selection| {
10598                if !selection.is_empty() {
10599                    selection.goal = SelectionGoal::None;
10600                }
10601                let (cursor, goal) = movement::down_by_rows(
10602                    map,
10603                    selection.start,
10604                    action.lines,
10605                    selection.goal,
10606                    false,
10607                    text_layout_details,
10608                );
10609                selection.collapse_to(cursor, goal);
10610            });
10611        })
10612    }
10613
10614    pub fn select_down_by_lines(
10615        &mut self,
10616        action: &SelectDownByLines,
10617        window: &mut Window,
10618        cx: &mut Context<Self>,
10619    ) {
10620        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10621        let text_layout_details = &self.text_layout_details(window);
10622        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10623            s.move_heads_with(|map, head, goal| {
10624                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
10625            })
10626        })
10627    }
10628
10629    pub fn select_up_by_lines(
10630        &mut self,
10631        action: &SelectUpByLines,
10632        window: &mut Window,
10633        cx: &mut Context<Self>,
10634    ) {
10635        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10636        let text_layout_details = &self.text_layout_details(window);
10637        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10638            s.move_heads_with(|map, head, goal| {
10639                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
10640            })
10641        })
10642    }
10643
10644    pub fn select_page_up(
10645        &mut self,
10646        _: &SelectPageUp,
10647        window: &mut Window,
10648        cx: &mut Context<Self>,
10649    ) {
10650        let Some(row_count) = self.visible_row_count() else {
10651            return;
10652        };
10653
10654        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10655
10656        let text_layout_details = &self.text_layout_details(window);
10657
10658        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10659            s.move_heads_with(|map, head, goal| {
10660                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
10661            })
10662        })
10663    }
10664
10665    pub fn move_page_up(
10666        &mut self,
10667        action: &MovePageUp,
10668        window: &mut Window,
10669        cx: &mut Context<Self>,
10670    ) {
10671        if self.take_rename(true, window, cx).is_some() {
10672            return;
10673        }
10674
10675        if self
10676            .context_menu
10677            .borrow_mut()
10678            .as_mut()
10679            .map(|menu| menu.select_first(self.completion_provider.as_deref(), cx))
10680            .unwrap_or(false)
10681        {
10682            return;
10683        }
10684
10685        if matches!(self.mode, EditorMode::SingleLine { .. }) {
10686            cx.propagate();
10687            return;
10688        }
10689
10690        let Some(row_count) = self.visible_row_count() else {
10691            return;
10692        };
10693
10694        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10695
10696        let autoscroll = if action.center_cursor {
10697            Autoscroll::center()
10698        } else {
10699            Autoscroll::fit()
10700        };
10701
10702        let text_layout_details = &self.text_layout_details(window);
10703
10704        self.change_selections(Some(autoscroll), window, cx, |s| {
10705            s.move_with(|map, selection| {
10706                if !selection.is_empty() {
10707                    selection.goal = SelectionGoal::None;
10708                }
10709                let (cursor, goal) = movement::up_by_rows(
10710                    map,
10711                    selection.end,
10712                    row_count,
10713                    selection.goal,
10714                    false,
10715                    text_layout_details,
10716                );
10717                selection.collapse_to(cursor, goal);
10718            });
10719        });
10720    }
10721
10722    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
10723        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10724        let text_layout_details = &self.text_layout_details(window);
10725        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10726            s.move_heads_with(|map, head, goal| {
10727                movement::up(map, head, goal, false, text_layout_details)
10728            })
10729        })
10730    }
10731
10732    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
10733        self.take_rename(true, window, cx);
10734
10735        if matches!(self.mode, EditorMode::SingleLine { .. }) {
10736            cx.propagate();
10737            return;
10738        }
10739
10740        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10741
10742        let text_layout_details = &self.text_layout_details(window);
10743        let selection_count = self.selections.count();
10744        let first_selection = self.selections.first_anchor();
10745
10746        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10747            s.move_with(|map, selection| {
10748                if !selection.is_empty() {
10749                    selection.goal = SelectionGoal::None;
10750                }
10751                let (cursor, goal) = movement::down(
10752                    map,
10753                    selection.end,
10754                    selection.goal,
10755                    false,
10756                    text_layout_details,
10757                );
10758                selection.collapse_to(cursor, goal);
10759            });
10760        });
10761
10762        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
10763        {
10764            cx.propagate();
10765        }
10766    }
10767
10768    pub fn select_page_down(
10769        &mut self,
10770        _: &SelectPageDown,
10771        window: &mut Window,
10772        cx: &mut Context<Self>,
10773    ) {
10774        let Some(row_count) = self.visible_row_count() else {
10775            return;
10776        };
10777
10778        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10779
10780        let text_layout_details = &self.text_layout_details(window);
10781
10782        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10783            s.move_heads_with(|map, head, goal| {
10784                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
10785            })
10786        })
10787    }
10788
10789    pub fn move_page_down(
10790        &mut self,
10791        action: &MovePageDown,
10792        window: &mut Window,
10793        cx: &mut Context<Self>,
10794    ) {
10795        if self.take_rename(true, window, cx).is_some() {
10796            return;
10797        }
10798
10799        if self
10800            .context_menu
10801            .borrow_mut()
10802            .as_mut()
10803            .map(|menu| menu.select_last(self.completion_provider.as_deref(), cx))
10804            .unwrap_or(false)
10805        {
10806            return;
10807        }
10808
10809        if matches!(self.mode, EditorMode::SingleLine { .. }) {
10810            cx.propagate();
10811            return;
10812        }
10813
10814        let Some(row_count) = self.visible_row_count() else {
10815            return;
10816        };
10817
10818        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10819
10820        let autoscroll = if action.center_cursor {
10821            Autoscroll::center()
10822        } else {
10823            Autoscroll::fit()
10824        };
10825
10826        let text_layout_details = &self.text_layout_details(window);
10827        self.change_selections(Some(autoscroll), window, cx, |s| {
10828            s.move_with(|map, selection| {
10829                if !selection.is_empty() {
10830                    selection.goal = SelectionGoal::None;
10831                }
10832                let (cursor, goal) = movement::down_by_rows(
10833                    map,
10834                    selection.end,
10835                    row_count,
10836                    selection.goal,
10837                    false,
10838                    text_layout_details,
10839                );
10840                selection.collapse_to(cursor, goal);
10841            });
10842        });
10843    }
10844
10845    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
10846        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10847        let text_layout_details = &self.text_layout_details(window);
10848        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10849            s.move_heads_with(|map, head, goal| {
10850                movement::down(map, head, goal, false, text_layout_details)
10851            })
10852        });
10853    }
10854
10855    pub fn context_menu_first(
10856        &mut self,
10857        _: &ContextMenuFirst,
10858        _window: &mut Window,
10859        cx: &mut Context<Self>,
10860    ) {
10861        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
10862            context_menu.select_first(self.completion_provider.as_deref(), cx);
10863        }
10864    }
10865
10866    pub fn context_menu_prev(
10867        &mut self,
10868        _: &ContextMenuPrevious,
10869        _window: &mut Window,
10870        cx: &mut Context<Self>,
10871    ) {
10872        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
10873            context_menu.select_prev(self.completion_provider.as_deref(), cx);
10874        }
10875    }
10876
10877    pub fn context_menu_next(
10878        &mut self,
10879        _: &ContextMenuNext,
10880        _window: &mut Window,
10881        cx: &mut Context<Self>,
10882    ) {
10883        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
10884            context_menu.select_next(self.completion_provider.as_deref(), cx);
10885        }
10886    }
10887
10888    pub fn context_menu_last(
10889        &mut self,
10890        _: &ContextMenuLast,
10891        _window: &mut Window,
10892        cx: &mut Context<Self>,
10893    ) {
10894        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
10895            context_menu.select_last(self.completion_provider.as_deref(), cx);
10896        }
10897    }
10898
10899    pub fn move_to_previous_word_start(
10900        &mut self,
10901        _: &MoveToPreviousWordStart,
10902        window: &mut Window,
10903        cx: &mut Context<Self>,
10904    ) {
10905        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10906        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10907            s.move_cursors_with(|map, head, _| {
10908                (
10909                    movement::previous_word_start(map, head),
10910                    SelectionGoal::None,
10911                )
10912            });
10913        })
10914    }
10915
10916    pub fn move_to_previous_subword_start(
10917        &mut self,
10918        _: &MoveToPreviousSubwordStart,
10919        window: &mut Window,
10920        cx: &mut Context<Self>,
10921    ) {
10922        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10923        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10924            s.move_cursors_with(|map, head, _| {
10925                (
10926                    movement::previous_subword_start(map, head),
10927                    SelectionGoal::None,
10928                )
10929            });
10930        })
10931    }
10932
10933    pub fn select_to_previous_word_start(
10934        &mut self,
10935        _: &SelectToPreviousWordStart,
10936        window: &mut Window,
10937        cx: &mut Context<Self>,
10938    ) {
10939        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10940        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10941            s.move_heads_with(|map, head, _| {
10942                (
10943                    movement::previous_word_start(map, head),
10944                    SelectionGoal::None,
10945                )
10946            });
10947        })
10948    }
10949
10950    pub fn select_to_previous_subword_start(
10951        &mut self,
10952        _: &SelectToPreviousSubwordStart,
10953        window: &mut Window,
10954        cx: &mut Context<Self>,
10955    ) {
10956        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
10957        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10958            s.move_heads_with(|map, head, _| {
10959                (
10960                    movement::previous_subword_start(map, head),
10961                    SelectionGoal::None,
10962                )
10963            });
10964        })
10965    }
10966
10967    pub fn delete_to_previous_word_start(
10968        &mut self,
10969        action: &DeleteToPreviousWordStart,
10970        window: &mut Window,
10971        cx: &mut Context<Self>,
10972    ) {
10973        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10974        self.transact(window, cx, |this, window, cx| {
10975            this.select_autoclose_pair(window, cx);
10976            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10977                s.move_with(|map, selection| {
10978                    if selection.is_empty() {
10979                        let cursor = if action.ignore_newlines {
10980                            movement::previous_word_start(map, selection.head())
10981                        } else {
10982                            movement::previous_word_start_or_newline(map, selection.head())
10983                        };
10984                        selection.set_head(cursor, SelectionGoal::None);
10985                    }
10986                });
10987            });
10988            this.insert("", window, cx);
10989        });
10990    }
10991
10992    pub fn delete_to_previous_subword_start(
10993        &mut self,
10994        _: &DeleteToPreviousSubwordStart,
10995        window: &mut Window,
10996        cx: &mut Context<Self>,
10997    ) {
10998        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10999        self.transact(window, cx, |this, window, cx| {
11000            this.select_autoclose_pair(window, cx);
11001            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11002                s.move_with(|map, selection| {
11003                    if selection.is_empty() {
11004                        let cursor = movement::previous_subword_start(map, selection.head());
11005                        selection.set_head(cursor, SelectionGoal::None);
11006                    }
11007                });
11008            });
11009            this.insert("", window, cx);
11010        });
11011    }
11012
11013    pub fn move_to_next_word_end(
11014        &mut self,
11015        _: &MoveToNextWordEnd,
11016        window: &mut Window,
11017        cx: &mut Context<Self>,
11018    ) {
11019        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11020        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11021            s.move_cursors_with(|map, head, _| {
11022                (movement::next_word_end(map, head), SelectionGoal::None)
11023            });
11024        })
11025    }
11026
11027    pub fn move_to_next_subword_end(
11028        &mut self,
11029        _: &MoveToNextSubwordEnd,
11030        window: &mut Window,
11031        cx: &mut Context<Self>,
11032    ) {
11033        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11034        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11035            s.move_cursors_with(|map, head, _| {
11036                (movement::next_subword_end(map, head), SelectionGoal::None)
11037            });
11038        })
11039    }
11040
11041    pub fn select_to_next_word_end(
11042        &mut self,
11043        _: &SelectToNextWordEnd,
11044        window: &mut Window,
11045        cx: &mut Context<Self>,
11046    ) {
11047        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11048        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11049            s.move_heads_with(|map, head, _| {
11050                (movement::next_word_end(map, head), SelectionGoal::None)
11051            });
11052        })
11053    }
11054
11055    pub fn select_to_next_subword_end(
11056        &mut self,
11057        _: &SelectToNextSubwordEnd,
11058        window: &mut Window,
11059        cx: &mut Context<Self>,
11060    ) {
11061        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11062        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11063            s.move_heads_with(|map, head, _| {
11064                (movement::next_subword_end(map, head), SelectionGoal::None)
11065            });
11066        })
11067    }
11068
11069    pub fn delete_to_next_word_end(
11070        &mut self,
11071        action: &DeleteToNextWordEnd,
11072        window: &mut Window,
11073        cx: &mut Context<Self>,
11074    ) {
11075        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11076        self.transact(window, cx, |this, window, cx| {
11077            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11078                s.move_with(|map, selection| {
11079                    if selection.is_empty() {
11080                        let cursor = if action.ignore_newlines {
11081                            movement::next_word_end(map, selection.head())
11082                        } else {
11083                            movement::next_word_end_or_newline(map, selection.head())
11084                        };
11085                        selection.set_head(cursor, SelectionGoal::None);
11086                    }
11087                });
11088            });
11089            this.insert("", window, cx);
11090        });
11091    }
11092
11093    pub fn delete_to_next_subword_end(
11094        &mut self,
11095        _: &DeleteToNextSubwordEnd,
11096        window: &mut Window,
11097        cx: &mut Context<Self>,
11098    ) {
11099        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11100        self.transact(window, cx, |this, window, cx| {
11101            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11102                s.move_with(|map, selection| {
11103                    if selection.is_empty() {
11104                        let cursor = movement::next_subword_end(map, selection.head());
11105                        selection.set_head(cursor, SelectionGoal::None);
11106                    }
11107                });
11108            });
11109            this.insert("", window, cx);
11110        });
11111    }
11112
11113    pub fn move_to_beginning_of_line(
11114        &mut self,
11115        action: &MoveToBeginningOfLine,
11116        window: &mut Window,
11117        cx: &mut Context<Self>,
11118    ) {
11119        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11120        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11121            s.move_cursors_with(|map, head, _| {
11122                (
11123                    movement::indented_line_beginning(
11124                        map,
11125                        head,
11126                        action.stop_at_soft_wraps,
11127                        action.stop_at_indent,
11128                    ),
11129                    SelectionGoal::None,
11130                )
11131            });
11132        })
11133    }
11134
11135    pub fn select_to_beginning_of_line(
11136        &mut self,
11137        action: &SelectToBeginningOfLine,
11138        window: &mut Window,
11139        cx: &mut Context<Self>,
11140    ) {
11141        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11142        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11143            s.move_heads_with(|map, head, _| {
11144                (
11145                    movement::indented_line_beginning(
11146                        map,
11147                        head,
11148                        action.stop_at_soft_wraps,
11149                        action.stop_at_indent,
11150                    ),
11151                    SelectionGoal::None,
11152                )
11153            });
11154        });
11155    }
11156
11157    pub fn delete_to_beginning_of_line(
11158        &mut self,
11159        action: &DeleteToBeginningOfLine,
11160        window: &mut Window,
11161        cx: &mut Context<Self>,
11162    ) {
11163        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11164        self.transact(window, cx, |this, window, cx| {
11165            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11166                s.move_with(|_, selection| {
11167                    selection.reversed = true;
11168                });
11169            });
11170
11171            this.select_to_beginning_of_line(
11172                &SelectToBeginningOfLine {
11173                    stop_at_soft_wraps: false,
11174                    stop_at_indent: action.stop_at_indent,
11175                },
11176                window,
11177                cx,
11178            );
11179            this.backspace(&Backspace, window, cx);
11180        });
11181    }
11182
11183    pub fn move_to_end_of_line(
11184        &mut self,
11185        action: &MoveToEndOfLine,
11186        window: &mut Window,
11187        cx: &mut Context<Self>,
11188    ) {
11189        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11190        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11191            s.move_cursors_with(|map, head, _| {
11192                (
11193                    movement::line_end(map, head, action.stop_at_soft_wraps),
11194                    SelectionGoal::None,
11195                )
11196            });
11197        })
11198    }
11199
11200    pub fn select_to_end_of_line(
11201        &mut self,
11202        action: &SelectToEndOfLine,
11203        window: &mut Window,
11204        cx: &mut Context<Self>,
11205    ) {
11206        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11207        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11208            s.move_heads_with(|map, head, _| {
11209                (
11210                    movement::line_end(map, head, action.stop_at_soft_wraps),
11211                    SelectionGoal::None,
11212                )
11213            });
11214        })
11215    }
11216
11217    pub fn delete_to_end_of_line(
11218        &mut self,
11219        _: &DeleteToEndOfLine,
11220        window: &mut Window,
11221        cx: &mut Context<Self>,
11222    ) {
11223        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11224        self.transact(window, cx, |this, window, cx| {
11225            this.select_to_end_of_line(
11226                &SelectToEndOfLine {
11227                    stop_at_soft_wraps: false,
11228                },
11229                window,
11230                cx,
11231            );
11232            this.delete(&Delete, window, cx);
11233        });
11234    }
11235
11236    pub fn cut_to_end_of_line(
11237        &mut self,
11238        _: &CutToEndOfLine,
11239        window: &mut Window,
11240        cx: &mut Context<Self>,
11241    ) {
11242        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11243        self.transact(window, cx, |this, window, cx| {
11244            this.select_to_end_of_line(
11245                &SelectToEndOfLine {
11246                    stop_at_soft_wraps: false,
11247                },
11248                window,
11249                cx,
11250            );
11251            this.cut(&Cut, window, cx);
11252        });
11253    }
11254
11255    pub fn move_to_start_of_paragraph(
11256        &mut self,
11257        _: &MoveToStartOfParagraph,
11258        window: &mut Window,
11259        cx: &mut Context<Self>,
11260    ) {
11261        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11262            cx.propagate();
11263            return;
11264        }
11265        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11266        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11267            s.move_with(|map, selection| {
11268                selection.collapse_to(
11269                    movement::start_of_paragraph(map, selection.head(), 1),
11270                    SelectionGoal::None,
11271                )
11272            });
11273        })
11274    }
11275
11276    pub fn move_to_end_of_paragraph(
11277        &mut self,
11278        _: &MoveToEndOfParagraph,
11279        window: &mut Window,
11280        cx: &mut Context<Self>,
11281    ) {
11282        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11283            cx.propagate();
11284            return;
11285        }
11286        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11287        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11288            s.move_with(|map, selection| {
11289                selection.collapse_to(
11290                    movement::end_of_paragraph(map, selection.head(), 1),
11291                    SelectionGoal::None,
11292                )
11293            });
11294        })
11295    }
11296
11297    pub fn select_to_start_of_paragraph(
11298        &mut self,
11299        _: &SelectToStartOfParagraph,
11300        window: &mut Window,
11301        cx: &mut Context<Self>,
11302    ) {
11303        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11304            cx.propagate();
11305            return;
11306        }
11307        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11308        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11309            s.move_heads_with(|map, head, _| {
11310                (
11311                    movement::start_of_paragraph(map, head, 1),
11312                    SelectionGoal::None,
11313                )
11314            });
11315        })
11316    }
11317
11318    pub fn select_to_end_of_paragraph(
11319        &mut self,
11320        _: &SelectToEndOfParagraph,
11321        window: &mut Window,
11322        cx: &mut Context<Self>,
11323    ) {
11324        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11325            cx.propagate();
11326            return;
11327        }
11328        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11329        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11330            s.move_heads_with(|map, head, _| {
11331                (
11332                    movement::end_of_paragraph(map, head, 1),
11333                    SelectionGoal::None,
11334                )
11335            });
11336        })
11337    }
11338
11339    pub fn move_to_start_of_excerpt(
11340        &mut self,
11341        _: &MoveToStartOfExcerpt,
11342        window: &mut Window,
11343        cx: &mut Context<Self>,
11344    ) {
11345        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11346            cx.propagate();
11347            return;
11348        }
11349        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11350        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11351            s.move_with(|map, selection| {
11352                selection.collapse_to(
11353                    movement::start_of_excerpt(
11354                        map,
11355                        selection.head(),
11356                        workspace::searchable::Direction::Prev,
11357                    ),
11358                    SelectionGoal::None,
11359                )
11360            });
11361        })
11362    }
11363
11364    pub fn move_to_start_of_next_excerpt(
11365        &mut self,
11366        _: &MoveToStartOfNextExcerpt,
11367        window: &mut Window,
11368        cx: &mut Context<Self>,
11369    ) {
11370        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11371            cx.propagate();
11372            return;
11373        }
11374
11375        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11376            s.move_with(|map, selection| {
11377                selection.collapse_to(
11378                    movement::start_of_excerpt(
11379                        map,
11380                        selection.head(),
11381                        workspace::searchable::Direction::Next,
11382                    ),
11383                    SelectionGoal::None,
11384                )
11385            });
11386        })
11387    }
11388
11389    pub fn move_to_end_of_excerpt(
11390        &mut self,
11391        _: &MoveToEndOfExcerpt,
11392        window: &mut Window,
11393        cx: &mut Context<Self>,
11394    ) {
11395        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11396            cx.propagate();
11397            return;
11398        }
11399        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11400        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11401            s.move_with(|map, selection| {
11402                selection.collapse_to(
11403                    movement::end_of_excerpt(
11404                        map,
11405                        selection.head(),
11406                        workspace::searchable::Direction::Next,
11407                    ),
11408                    SelectionGoal::None,
11409                )
11410            });
11411        })
11412    }
11413
11414    pub fn move_to_end_of_previous_excerpt(
11415        &mut self,
11416        _: &MoveToEndOfPreviousExcerpt,
11417        window: &mut Window,
11418        cx: &mut Context<Self>,
11419    ) {
11420        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11421            cx.propagate();
11422            return;
11423        }
11424        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11425        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11426            s.move_with(|map, selection| {
11427                selection.collapse_to(
11428                    movement::end_of_excerpt(
11429                        map,
11430                        selection.head(),
11431                        workspace::searchable::Direction::Prev,
11432                    ),
11433                    SelectionGoal::None,
11434                )
11435            });
11436        })
11437    }
11438
11439    pub fn select_to_start_of_excerpt(
11440        &mut self,
11441        _: &SelectToStartOfExcerpt,
11442        window: &mut Window,
11443        cx: &mut Context<Self>,
11444    ) {
11445        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11446            cx.propagate();
11447            return;
11448        }
11449        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11450        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11451            s.move_heads_with(|map, head, _| {
11452                (
11453                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
11454                    SelectionGoal::None,
11455                )
11456            });
11457        })
11458    }
11459
11460    pub fn select_to_start_of_next_excerpt(
11461        &mut self,
11462        _: &SelectToStartOfNextExcerpt,
11463        window: &mut Window,
11464        cx: &mut Context<Self>,
11465    ) {
11466        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11467            cx.propagate();
11468            return;
11469        }
11470        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11471        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11472            s.move_heads_with(|map, head, _| {
11473                (
11474                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
11475                    SelectionGoal::None,
11476                )
11477            });
11478        })
11479    }
11480
11481    pub fn select_to_end_of_excerpt(
11482        &mut self,
11483        _: &SelectToEndOfExcerpt,
11484        window: &mut Window,
11485        cx: &mut Context<Self>,
11486    ) {
11487        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11488            cx.propagate();
11489            return;
11490        }
11491        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11492        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11493            s.move_heads_with(|map, head, _| {
11494                (
11495                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
11496                    SelectionGoal::None,
11497                )
11498            });
11499        })
11500    }
11501
11502    pub fn select_to_end_of_previous_excerpt(
11503        &mut self,
11504        _: &SelectToEndOfPreviousExcerpt,
11505        window: &mut Window,
11506        cx: &mut Context<Self>,
11507    ) {
11508        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11509            cx.propagate();
11510            return;
11511        }
11512        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11513        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11514            s.move_heads_with(|map, head, _| {
11515                (
11516                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
11517                    SelectionGoal::None,
11518                )
11519            });
11520        })
11521    }
11522
11523    pub fn move_to_beginning(
11524        &mut self,
11525        _: &MoveToBeginning,
11526        window: &mut Window,
11527        cx: &mut Context<Self>,
11528    ) {
11529        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11530            cx.propagate();
11531            return;
11532        }
11533        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11534        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11535            s.select_ranges(vec![0..0]);
11536        });
11537    }
11538
11539    pub fn select_to_beginning(
11540        &mut self,
11541        _: &SelectToBeginning,
11542        window: &mut Window,
11543        cx: &mut Context<Self>,
11544    ) {
11545        let mut selection = self.selections.last::<Point>(cx);
11546        selection.set_head(Point::zero(), SelectionGoal::None);
11547        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11548        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11549            s.select(vec![selection]);
11550        });
11551    }
11552
11553    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
11554        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11555            cx.propagate();
11556            return;
11557        }
11558        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11559        let cursor = self.buffer.read(cx).read(cx).len();
11560        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11561            s.select_ranges(vec![cursor..cursor])
11562        });
11563    }
11564
11565    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
11566        self.nav_history = nav_history;
11567    }
11568
11569    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
11570        self.nav_history.as_ref()
11571    }
11572
11573    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
11574        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
11575    }
11576
11577    fn push_to_nav_history(
11578        &mut self,
11579        cursor_anchor: Anchor,
11580        new_position: Option<Point>,
11581        is_deactivate: bool,
11582        cx: &mut Context<Self>,
11583    ) {
11584        if let Some(nav_history) = self.nav_history.as_mut() {
11585            let buffer = self.buffer.read(cx).read(cx);
11586            let cursor_position = cursor_anchor.to_point(&buffer);
11587            let scroll_state = self.scroll_manager.anchor();
11588            let scroll_top_row = scroll_state.top_row(&buffer);
11589            drop(buffer);
11590
11591            if let Some(new_position) = new_position {
11592                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
11593                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
11594                    return;
11595                }
11596            }
11597
11598            nav_history.push(
11599                Some(NavigationData {
11600                    cursor_anchor,
11601                    cursor_position,
11602                    scroll_anchor: scroll_state,
11603                    scroll_top_row,
11604                }),
11605                cx,
11606            );
11607            cx.emit(EditorEvent::PushedToNavHistory {
11608                anchor: cursor_anchor,
11609                is_deactivate,
11610            })
11611        }
11612    }
11613
11614    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
11615        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11616        let buffer = self.buffer.read(cx).snapshot(cx);
11617        let mut selection = self.selections.first::<usize>(cx);
11618        selection.set_head(buffer.len(), SelectionGoal::None);
11619        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11620            s.select(vec![selection]);
11621        });
11622    }
11623
11624    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
11625        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11626        let end = self.buffer.read(cx).read(cx).len();
11627        self.change_selections(None, window, cx, |s| {
11628            s.select_ranges(vec![0..end]);
11629        });
11630    }
11631
11632    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
11633        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11634        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11635        let mut selections = self.selections.all::<Point>(cx);
11636        let max_point = display_map.buffer_snapshot.max_point();
11637        for selection in &mut selections {
11638            let rows = selection.spanned_rows(true, &display_map);
11639            selection.start = Point::new(rows.start.0, 0);
11640            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
11641            selection.reversed = false;
11642        }
11643        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11644            s.select(selections);
11645        });
11646    }
11647
11648    pub fn split_selection_into_lines(
11649        &mut self,
11650        _: &SplitSelectionIntoLines,
11651        window: &mut Window,
11652        cx: &mut Context<Self>,
11653    ) {
11654        let selections = self
11655            .selections
11656            .all::<Point>(cx)
11657            .into_iter()
11658            .map(|selection| selection.start..selection.end)
11659            .collect::<Vec<_>>();
11660        self.unfold_ranges(&selections, true, true, cx);
11661
11662        let mut new_selection_ranges = Vec::new();
11663        {
11664            let buffer = self.buffer.read(cx).read(cx);
11665            for selection in selections {
11666                for row in selection.start.row..selection.end.row {
11667                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11668                    new_selection_ranges.push(cursor..cursor);
11669                }
11670
11671                let is_multiline_selection = selection.start.row != selection.end.row;
11672                // Don't insert last one if it's a multi-line selection ending at the start of a line,
11673                // so this action feels more ergonomic when paired with other selection operations
11674                let should_skip_last = is_multiline_selection && selection.end.column == 0;
11675                if !should_skip_last {
11676                    new_selection_ranges.push(selection.end..selection.end);
11677                }
11678            }
11679        }
11680        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11681            s.select_ranges(new_selection_ranges);
11682        });
11683    }
11684
11685    pub fn add_selection_above(
11686        &mut self,
11687        _: &AddSelectionAbove,
11688        window: &mut Window,
11689        cx: &mut Context<Self>,
11690    ) {
11691        self.add_selection(true, window, cx);
11692    }
11693
11694    pub fn add_selection_below(
11695        &mut self,
11696        _: &AddSelectionBelow,
11697        window: &mut Window,
11698        cx: &mut Context<Self>,
11699    ) {
11700        self.add_selection(false, window, cx);
11701    }
11702
11703    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
11704        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11705
11706        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11707        let mut selections = self.selections.all::<Point>(cx);
11708        let text_layout_details = self.text_layout_details(window);
11709        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
11710            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
11711            let range = oldest_selection.display_range(&display_map).sorted();
11712
11713            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
11714            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
11715            let positions = start_x.min(end_x)..start_x.max(end_x);
11716
11717            selections.clear();
11718            let mut stack = Vec::new();
11719            for row in range.start.row().0..=range.end.row().0 {
11720                if let Some(selection) = self.selections.build_columnar_selection(
11721                    &display_map,
11722                    DisplayRow(row),
11723                    &positions,
11724                    oldest_selection.reversed,
11725                    &text_layout_details,
11726                ) {
11727                    stack.push(selection.id);
11728                    selections.push(selection);
11729                }
11730            }
11731
11732            if above {
11733                stack.reverse();
11734            }
11735
11736            AddSelectionsState { above, stack }
11737        });
11738
11739        let last_added_selection = *state.stack.last().unwrap();
11740        let mut new_selections = Vec::new();
11741        if above == state.above {
11742            let end_row = if above {
11743                DisplayRow(0)
11744            } else {
11745                display_map.max_point().row()
11746            };
11747
11748            'outer: for selection in selections {
11749                if selection.id == last_added_selection {
11750                    let range = selection.display_range(&display_map).sorted();
11751                    debug_assert_eq!(range.start.row(), range.end.row());
11752                    let mut row = range.start.row();
11753                    let positions =
11754                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
11755                            px(start)..px(end)
11756                        } else {
11757                            let start_x =
11758                                display_map.x_for_display_point(range.start, &text_layout_details);
11759                            let end_x =
11760                                display_map.x_for_display_point(range.end, &text_layout_details);
11761                            start_x.min(end_x)..start_x.max(end_x)
11762                        };
11763
11764                    while row != end_row {
11765                        if above {
11766                            row.0 -= 1;
11767                        } else {
11768                            row.0 += 1;
11769                        }
11770
11771                        if let Some(new_selection) = self.selections.build_columnar_selection(
11772                            &display_map,
11773                            row,
11774                            &positions,
11775                            selection.reversed,
11776                            &text_layout_details,
11777                        ) {
11778                            state.stack.push(new_selection.id);
11779                            if above {
11780                                new_selections.push(new_selection);
11781                                new_selections.push(selection);
11782                            } else {
11783                                new_selections.push(selection);
11784                                new_selections.push(new_selection);
11785                            }
11786
11787                            continue 'outer;
11788                        }
11789                    }
11790                }
11791
11792                new_selections.push(selection);
11793            }
11794        } else {
11795            new_selections = selections;
11796            new_selections.retain(|s| s.id != last_added_selection);
11797            state.stack.pop();
11798        }
11799
11800        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11801            s.select(new_selections);
11802        });
11803        if state.stack.len() > 1 {
11804            self.add_selections_state = Some(state);
11805        }
11806    }
11807
11808    pub fn select_next_match_internal(
11809        &mut self,
11810        display_map: &DisplaySnapshot,
11811        replace_newest: bool,
11812        autoscroll: Option<Autoscroll>,
11813        window: &mut Window,
11814        cx: &mut Context<Self>,
11815    ) -> Result<()> {
11816        fn select_next_match_ranges(
11817            this: &mut Editor,
11818            range: Range<usize>,
11819            replace_newest: bool,
11820            auto_scroll: Option<Autoscroll>,
11821            window: &mut Window,
11822            cx: &mut Context<Editor>,
11823        ) {
11824            this.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
11825            this.change_selections(auto_scroll, window, cx, |s| {
11826                if replace_newest {
11827                    s.delete(s.newest_anchor().id);
11828                }
11829                s.insert_range(range.clone());
11830            });
11831        }
11832
11833        let buffer = &display_map.buffer_snapshot;
11834        let mut selections = self.selections.all::<usize>(cx);
11835        if let Some(mut select_next_state) = self.select_next_state.take() {
11836            let query = &select_next_state.query;
11837            if !select_next_state.done {
11838                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
11839                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
11840                let mut next_selected_range = None;
11841
11842                let bytes_after_last_selection =
11843                    buffer.bytes_in_range(last_selection.end..buffer.len());
11844                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
11845                let query_matches = query
11846                    .stream_find_iter(bytes_after_last_selection)
11847                    .map(|result| (last_selection.end, result))
11848                    .chain(
11849                        query
11850                            .stream_find_iter(bytes_before_first_selection)
11851                            .map(|result| (0, result)),
11852                    );
11853
11854                for (start_offset, query_match) in query_matches {
11855                    let query_match = query_match.unwrap(); // can only fail due to I/O
11856                    let offset_range =
11857                        start_offset + query_match.start()..start_offset + query_match.end();
11858                    let display_range = offset_range.start.to_display_point(display_map)
11859                        ..offset_range.end.to_display_point(display_map);
11860
11861                    if !select_next_state.wordwise
11862                        || (!movement::is_inside_word(display_map, display_range.start)
11863                            && !movement::is_inside_word(display_map, display_range.end))
11864                    {
11865                        // TODO: This is n^2, because we might check all the selections
11866                        if !selections
11867                            .iter()
11868                            .any(|selection| selection.range().overlaps(&offset_range))
11869                        {
11870                            next_selected_range = Some(offset_range);
11871                            break;
11872                        }
11873                    }
11874                }
11875
11876                if let Some(next_selected_range) = next_selected_range {
11877                    select_next_match_ranges(
11878                        self,
11879                        next_selected_range,
11880                        replace_newest,
11881                        autoscroll,
11882                        window,
11883                        cx,
11884                    );
11885                } else {
11886                    select_next_state.done = true;
11887                }
11888            }
11889
11890            self.select_next_state = Some(select_next_state);
11891        } else {
11892            let mut only_carets = true;
11893            let mut same_text_selected = true;
11894            let mut selected_text = None;
11895
11896            let mut selections_iter = selections.iter().peekable();
11897            while let Some(selection) = selections_iter.next() {
11898                if selection.start != selection.end {
11899                    only_carets = false;
11900                }
11901
11902                if same_text_selected {
11903                    if selected_text.is_none() {
11904                        selected_text =
11905                            Some(buffer.text_for_range(selection.range()).collect::<String>());
11906                    }
11907
11908                    if let Some(next_selection) = selections_iter.peek() {
11909                        if next_selection.range().len() == selection.range().len() {
11910                            let next_selected_text = buffer
11911                                .text_for_range(next_selection.range())
11912                                .collect::<String>();
11913                            if Some(next_selected_text) != selected_text {
11914                                same_text_selected = false;
11915                                selected_text = None;
11916                            }
11917                        } else {
11918                            same_text_selected = false;
11919                            selected_text = None;
11920                        }
11921                    }
11922                }
11923            }
11924
11925            if only_carets {
11926                for selection in &mut selections {
11927                    let word_range = movement::surrounding_word(
11928                        display_map,
11929                        selection.start.to_display_point(display_map),
11930                    );
11931                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
11932                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
11933                    selection.goal = SelectionGoal::None;
11934                    selection.reversed = false;
11935                    select_next_match_ranges(
11936                        self,
11937                        selection.start..selection.end,
11938                        replace_newest,
11939                        autoscroll,
11940                        window,
11941                        cx,
11942                    );
11943                }
11944
11945                if selections.len() == 1 {
11946                    let selection = selections
11947                        .last()
11948                        .expect("ensured that there's only one selection");
11949                    let query = buffer
11950                        .text_for_range(selection.start..selection.end)
11951                        .collect::<String>();
11952                    let is_empty = query.is_empty();
11953                    let select_state = SelectNextState {
11954                        query: AhoCorasick::new(&[query])?,
11955                        wordwise: true,
11956                        done: is_empty,
11957                    };
11958                    self.select_next_state = Some(select_state);
11959                } else {
11960                    self.select_next_state = None;
11961                }
11962            } else if let Some(selected_text) = selected_text {
11963                self.select_next_state = Some(SelectNextState {
11964                    query: AhoCorasick::new(&[selected_text])?,
11965                    wordwise: false,
11966                    done: false,
11967                });
11968                self.select_next_match_internal(
11969                    display_map,
11970                    replace_newest,
11971                    autoscroll,
11972                    window,
11973                    cx,
11974                )?;
11975            }
11976        }
11977        Ok(())
11978    }
11979
11980    pub fn select_all_matches(
11981        &mut self,
11982        _action: &SelectAllMatches,
11983        window: &mut Window,
11984        cx: &mut Context<Self>,
11985    ) -> Result<()> {
11986        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11987
11988        self.push_to_selection_history();
11989        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11990
11991        self.select_next_match_internal(&display_map, false, None, window, cx)?;
11992        let Some(select_next_state) = self.select_next_state.as_mut() else {
11993            return Ok(());
11994        };
11995        if select_next_state.done {
11996            return Ok(());
11997        }
11998
11999        let mut new_selections = Vec::new();
12000
12001        let reversed = self.selections.oldest::<usize>(cx).reversed;
12002        let buffer = &display_map.buffer_snapshot;
12003        let query_matches = select_next_state
12004            .query
12005            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
12006
12007        for query_match in query_matches.into_iter() {
12008            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
12009            let offset_range = if reversed {
12010                query_match.end()..query_match.start()
12011            } else {
12012                query_match.start()..query_match.end()
12013            };
12014            let display_range = offset_range.start.to_display_point(&display_map)
12015                ..offset_range.end.to_display_point(&display_map);
12016
12017            if !select_next_state.wordwise
12018                || (!movement::is_inside_word(&display_map, display_range.start)
12019                    && !movement::is_inside_word(&display_map, display_range.end))
12020            {
12021                new_selections.push(offset_range.start..offset_range.end);
12022            }
12023        }
12024
12025        select_next_state.done = true;
12026        self.unfold_ranges(&new_selections.clone(), false, false, cx);
12027        self.change_selections(None, window, cx, |selections| {
12028            selections.select_ranges(new_selections)
12029        });
12030
12031        Ok(())
12032    }
12033
12034    pub fn select_next(
12035        &mut self,
12036        action: &SelectNext,
12037        window: &mut Window,
12038        cx: &mut Context<Self>,
12039    ) -> Result<()> {
12040        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12041        self.push_to_selection_history();
12042        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12043        self.select_next_match_internal(
12044            &display_map,
12045            action.replace_newest,
12046            Some(Autoscroll::newest()),
12047            window,
12048            cx,
12049        )?;
12050        Ok(())
12051    }
12052
12053    pub fn select_previous(
12054        &mut self,
12055        action: &SelectPrevious,
12056        window: &mut Window,
12057        cx: &mut Context<Self>,
12058    ) -> Result<()> {
12059        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12060        self.push_to_selection_history();
12061        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12062        let buffer = &display_map.buffer_snapshot;
12063        let mut selections = self.selections.all::<usize>(cx);
12064        if let Some(mut select_prev_state) = self.select_prev_state.take() {
12065            let query = &select_prev_state.query;
12066            if !select_prev_state.done {
12067                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12068                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12069                let mut next_selected_range = None;
12070                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
12071                let bytes_before_last_selection =
12072                    buffer.reversed_bytes_in_range(0..last_selection.start);
12073                let bytes_after_first_selection =
12074                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
12075                let query_matches = query
12076                    .stream_find_iter(bytes_before_last_selection)
12077                    .map(|result| (last_selection.start, result))
12078                    .chain(
12079                        query
12080                            .stream_find_iter(bytes_after_first_selection)
12081                            .map(|result| (buffer.len(), result)),
12082                    );
12083                for (end_offset, query_match) in query_matches {
12084                    let query_match = query_match.unwrap(); // can only fail due to I/O
12085                    let offset_range =
12086                        end_offset - query_match.end()..end_offset - query_match.start();
12087                    let display_range = offset_range.start.to_display_point(&display_map)
12088                        ..offset_range.end.to_display_point(&display_map);
12089
12090                    if !select_prev_state.wordwise
12091                        || (!movement::is_inside_word(&display_map, display_range.start)
12092                            && !movement::is_inside_word(&display_map, display_range.end))
12093                    {
12094                        next_selected_range = Some(offset_range);
12095                        break;
12096                    }
12097                }
12098
12099                if let Some(next_selected_range) = next_selected_range {
12100                    self.unfold_ranges(&[next_selected_range.clone()], false, true, cx);
12101                    self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
12102                        if action.replace_newest {
12103                            s.delete(s.newest_anchor().id);
12104                        }
12105                        s.insert_range(next_selected_range);
12106                    });
12107                } else {
12108                    select_prev_state.done = true;
12109                }
12110            }
12111
12112            self.select_prev_state = Some(select_prev_state);
12113        } else {
12114            let mut only_carets = true;
12115            let mut same_text_selected = true;
12116            let mut selected_text = None;
12117
12118            let mut selections_iter = selections.iter().peekable();
12119            while let Some(selection) = selections_iter.next() {
12120                if selection.start != selection.end {
12121                    only_carets = false;
12122                }
12123
12124                if same_text_selected {
12125                    if selected_text.is_none() {
12126                        selected_text =
12127                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12128                    }
12129
12130                    if let Some(next_selection) = selections_iter.peek() {
12131                        if next_selection.range().len() == selection.range().len() {
12132                            let next_selected_text = buffer
12133                                .text_for_range(next_selection.range())
12134                                .collect::<String>();
12135                            if Some(next_selected_text) != selected_text {
12136                                same_text_selected = false;
12137                                selected_text = None;
12138                            }
12139                        } else {
12140                            same_text_selected = false;
12141                            selected_text = None;
12142                        }
12143                    }
12144                }
12145            }
12146
12147            if only_carets {
12148                for selection in &mut selections {
12149                    let word_range = movement::surrounding_word(
12150                        &display_map,
12151                        selection.start.to_display_point(&display_map),
12152                    );
12153                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
12154                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
12155                    selection.goal = SelectionGoal::None;
12156                    selection.reversed = false;
12157                }
12158                if selections.len() == 1 {
12159                    let selection = selections
12160                        .last()
12161                        .expect("ensured that there's only one selection");
12162                    let query = buffer
12163                        .text_for_range(selection.start..selection.end)
12164                        .collect::<String>();
12165                    let is_empty = query.is_empty();
12166                    let select_state = SelectNextState {
12167                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
12168                        wordwise: true,
12169                        done: is_empty,
12170                    };
12171                    self.select_prev_state = Some(select_state);
12172                } else {
12173                    self.select_prev_state = None;
12174                }
12175
12176                self.unfold_ranges(
12177                    &selections.iter().map(|s| s.range()).collect::<Vec<_>>(),
12178                    false,
12179                    true,
12180                    cx,
12181                );
12182                self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
12183                    s.select(selections);
12184                });
12185            } else if let Some(selected_text) = selected_text {
12186                self.select_prev_state = Some(SelectNextState {
12187                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
12188                    wordwise: false,
12189                    done: false,
12190                });
12191                self.select_previous(action, window, cx)?;
12192            }
12193        }
12194        Ok(())
12195    }
12196
12197    pub fn find_next_match(
12198        &mut self,
12199        _: &FindNextMatch,
12200        window: &mut Window,
12201        cx: &mut Context<Self>,
12202    ) -> Result<()> {
12203        let selections = self.selections.disjoint_anchors();
12204        match selections.first() {
12205            Some(first) if selections.len() >= 2 => {
12206                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12207                    s.select_ranges([first.range()]);
12208                });
12209            }
12210            _ => self.select_next(
12211                &SelectNext {
12212                    replace_newest: true,
12213                },
12214                window,
12215                cx,
12216            )?,
12217        }
12218        Ok(())
12219    }
12220
12221    pub fn find_previous_match(
12222        &mut self,
12223        _: &FindPreviousMatch,
12224        window: &mut Window,
12225        cx: &mut Context<Self>,
12226    ) -> Result<()> {
12227        let selections = self.selections.disjoint_anchors();
12228        match selections.last() {
12229            Some(last) if selections.len() >= 2 => {
12230                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12231                    s.select_ranges([last.range()]);
12232                });
12233            }
12234            _ => self.select_previous(
12235                &SelectPrevious {
12236                    replace_newest: true,
12237                },
12238                window,
12239                cx,
12240            )?,
12241        }
12242        Ok(())
12243    }
12244
12245    pub fn toggle_comments(
12246        &mut self,
12247        action: &ToggleComments,
12248        window: &mut Window,
12249        cx: &mut Context<Self>,
12250    ) {
12251        if self.read_only(cx) {
12252            return;
12253        }
12254        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12255        let text_layout_details = &self.text_layout_details(window);
12256        self.transact(window, cx, |this, window, cx| {
12257            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
12258            let mut edits = Vec::new();
12259            let mut selection_edit_ranges = Vec::new();
12260            let mut last_toggled_row = None;
12261            let snapshot = this.buffer.read(cx).read(cx);
12262            let empty_str: Arc<str> = Arc::default();
12263            let mut suffixes_inserted = Vec::new();
12264            let ignore_indent = action.ignore_indent;
12265
12266            fn comment_prefix_range(
12267                snapshot: &MultiBufferSnapshot,
12268                row: MultiBufferRow,
12269                comment_prefix: &str,
12270                comment_prefix_whitespace: &str,
12271                ignore_indent: bool,
12272            ) -> Range<Point> {
12273                let indent_size = if ignore_indent {
12274                    0
12275                } else {
12276                    snapshot.indent_size_for_line(row).len
12277                };
12278
12279                let start = Point::new(row.0, indent_size);
12280
12281                let mut line_bytes = snapshot
12282                    .bytes_in_range(start..snapshot.max_point())
12283                    .flatten()
12284                    .copied();
12285
12286                // If this line currently begins with the line comment prefix, then record
12287                // the range containing the prefix.
12288                if line_bytes
12289                    .by_ref()
12290                    .take(comment_prefix.len())
12291                    .eq(comment_prefix.bytes())
12292                {
12293                    // Include any whitespace that matches the comment prefix.
12294                    let matching_whitespace_len = line_bytes
12295                        .zip(comment_prefix_whitespace.bytes())
12296                        .take_while(|(a, b)| a == b)
12297                        .count() as u32;
12298                    let end = Point::new(
12299                        start.row,
12300                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
12301                    );
12302                    start..end
12303                } else {
12304                    start..start
12305                }
12306            }
12307
12308            fn comment_suffix_range(
12309                snapshot: &MultiBufferSnapshot,
12310                row: MultiBufferRow,
12311                comment_suffix: &str,
12312                comment_suffix_has_leading_space: bool,
12313            ) -> Range<Point> {
12314                let end = Point::new(row.0, snapshot.line_len(row));
12315                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
12316
12317                let mut line_end_bytes = snapshot
12318                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
12319                    .flatten()
12320                    .copied();
12321
12322                let leading_space_len = if suffix_start_column > 0
12323                    && line_end_bytes.next() == Some(b' ')
12324                    && comment_suffix_has_leading_space
12325                {
12326                    1
12327                } else {
12328                    0
12329                };
12330
12331                // If this line currently begins with the line comment prefix, then record
12332                // the range containing the prefix.
12333                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
12334                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
12335                    start..end
12336                } else {
12337                    end..end
12338                }
12339            }
12340
12341            // TODO: Handle selections that cross excerpts
12342            for selection in &mut selections {
12343                let start_column = snapshot
12344                    .indent_size_for_line(MultiBufferRow(selection.start.row))
12345                    .len;
12346                let language = if let Some(language) =
12347                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
12348                {
12349                    language
12350                } else {
12351                    continue;
12352                };
12353
12354                selection_edit_ranges.clear();
12355
12356                // If multiple selections contain a given row, avoid processing that
12357                // row more than once.
12358                let mut start_row = MultiBufferRow(selection.start.row);
12359                if last_toggled_row == Some(start_row) {
12360                    start_row = start_row.next_row();
12361                }
12362                let end_row =
12363                    if selection.end.row > selection.start.row && selection.end.column == 0 {
12364                        MultiBufferRow(selection.end.row - 1)
12365                    } else {
12366                        MultiBufferRow(selection.end.row)
12367                    };
12368                last_toggled_row = Some(end_row);
12369
12370                if start_row > end_row {
12371                    continue;
12372                }
12373
12374                // If the language has line comments, toggle those.
12375                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
12376
12377                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
12378                if ignore_indent {
12379                    full_comment_prefixes = full_comment_prefixes
12380                        .into_iter()
12381                        .map(|s| Arc::from(s.trim_end()))
12382                        .collect();
12383                }
12384
12385                if !full_comment_prefixes.is_empty() {
12386                    let first_prefix = full_comment_prefixes
12387                        .first()
12388                        .expect("prefixes is non-empty");
12389                    let prefix_trimmed_lengths = full_comment_prefixes
12390                        .iter()
12391                        .map(|p| p.trim_end_matches(' ').len())
12392                        .collect::<SmallVec<[usize; 4]>>();
12393
12394                    let mut all_selection_lines_are_comments = true;
12395
12396                    for row in start_row.0..=end_row.0 {
12397                        let row = MultiBufferRow(row);
12398                        if start_row < end_row && snapshot.is_line_blank(row) {
12399                            continue;
12400                        }
12401
12402                        let prefix_range = full_comment_prefixes
12403                            .iter()
12404                            .zip(prefix_trimmed_lengths.iter().copied())
12405                            .map(|(prefix, trimmed_prefix_len)| {
12406                                comment_prefix_range(
12407                                    snapshot.deref(),
12408                                    row,
12409                                    &prefix[..trimmed_prefix_len],
12410                                    &prefix[trimmed_prefix_len..],
12411                                    ignore_indent,
12412                                )
12413                            })
12414                            .max_by_key(|range| range.end.column - range.start.column)
12415                            .expect("prefixes is non-empty");
12416
12417                        if prefix_range.is_empty() {
12418                            all_selection_lines_are_comments = false;
12419                        }
12420
12421                        selection_edit_ranges.push(prefix_range);
12422                    }
12423
12424                    if all_selection_lines_are_comments {
12425                        edits.extend(
12426                            selection_edit_ranges
12427                                .iter()
12428                                .cloned()
12429                                .map(|range| (range, empty_str.clone())),
12430                        );
12431                    } else {
12432                        let min_column = selection_edit_ranges
12433                            .iter()
12434                            .map(|range| range.start.column)
12435                            .min()
12436                            .unwrap_or(0);
12437                        edits.extend(selection_edit_ranges.iter().map(|range| {
12438                            let position = Point::new(range.start.row, min_column);
12439                            (position..position, first_prefix.clone())
12440                        }));
12441                    }
12442                } else if let Some((full_comment_prefix, comment_suffix)) =
12443                    language.block_comment_delimiters()
12444                {
12445                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
12446                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
12447                    let prefix_range = comment_prefix_range(
12448                        snapshot.deref(),
12449                        start_row,
12450                        comment_prefix,
12451                        comment_prefix_whitespace,
12452                        ignore_indent,
12453                    );
12454                    let suffix_range = comment_suffix_range(
12455                        snapshot.deref(),
12456                        end_row,
12457                        comment_suffix.trim_start_matches(' '),
12458                        comment_suffix.starts_with(' '),
12459                    );
12460
12461                    if prefix_range.is_empty() || suffix_range.is_empty() {
12462                        edits.push((
12463                            prefix_range.start..prefix_range.start,
12464                            full_comment_prefix.clone(),
12465                        ));
12466                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
12467                        suffixes_inserted.push((end_row, comment_suffix.len()));
12468                    } else {
12469                        edits.push((prefix_range, empty_str.clone()));
12470                        edits.push((suffix_range, empty_str.clone()));
12471                    }
12472                } else {
12473                    continue;
12474                }
12475            }
12476
12477            drop(snapshot);
12478            this.buffer.update(cx, |buffer, cx| {
12479                buffer.edit(edits, None, cx);
12480            });
12481
12482            // Adjust selections so that they end before any comment suffixes that
12483            // were inserted.
12484            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
12485            let mut selections = this.selections.all::<Point>(cx);
12486            let snapshot = this.buffer.read(cx).read(cx);
12487            for selection in &mut selections {
12488                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
12489                    match row.cmp(&MultiBufferRow(selection.end.row)) {
12490                        Ordering::Less => {
12491                            suffixes_inserted.next();
12492                            continue;
12493                        }
12494                        Ordering::Greater => break,
12495                        Ordering::Equal => {
12496                            if selection.end.column == snapshot.line_len(row) {
12497                                if selection.is_empty() {
12498                                    selection.start.column -= suffix_len as u32;
12499                                }
12500                                selection.end.column -= suffix_len as u32;
12501                            }
12502                            break;
12503                        }
12504                    }
12505                }
12506            }
12507
12508            drop(snapshot);
12509            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12510                s.select(selections)
12511            });
12512
12513            let selections = this.selections.all::<Point>(cx);
12514            let selections_on_single_row = selections.windows(2).all(|selections| {
12515                selections[0].start.row == selections[1].start.row
12516                    && selections[0].end.row == selections[1].end.row
12517                    && selections[0].start.row == selections[0].end.row
12518            });
12519            let selections_selecting = selections
12520                .iter()
12521                .any(|selection| selection.start != selection.end);
12522            let advance_downwards = action.advance_downwards
12523                && selections_on_single_row
12524                && !selections_selecting
12525                && !matches!(this.mode, EditorMode::SingleLine { .. });
12526
12527            if advance_downwards {
12528                let snapshot = this.buffer.read(cx).snapshot(cx);
12529
12530                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12531                    s.move_cursors_with(|display_snapshot, display_point, _| {
12532                        let mut point = display_point.to_point(display_snapshot);
12533                        point.row += 1;
12534                        point = snapshot.clip_point(point, Bias::Left);
12535                        let display_point = point.to_display_point(display_snapshot);
12536                        let goal = SelectionGoal::HorizontalPosition(
12537                            display_snapshot
12538                                .x_for_display_point(display_point, text_layout_details)
12539                                .into(),
12540                        );
12541                        (display_point, goal)
12542                    })
12543                });
12544            }
12545        });
12546    }
12547
12548    pub fn select_enclosing_symbol(
12549        &mut self,
12550        _: &SelectEnclosingSymbol,
12551        window: &mut Window,
12552        cx: &mut Context<Self>,
12553    ) {
12554        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12555
12556        let buffer = self.buffer.read(cx).snapshot(cx);
12557        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
12558
12559        fn update_selection(
12560            selection: &Selection<usize>,
12561            buffer_snap: &MultiBufferSnapshot,
12562        ) -> Option<Selection<usize>> {
12563            let cursor = selection.head();
12564            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
12565            for symbol in symbols.iter().rev() {
12566                let start = symbol.range.start.to_offset(buffer_snap);
12567                let end = symbol.range.end.to_offset(buffer_snap);
12568                let new_range = start..end;
12569                if start < selection.start || end > selection.end {
12570                    return Some(Selection {
12571                        id: selection.id,
12572                        start: new_range.start,
12573                        end: new_range.end,
12574                        goal: SelectionGoal::None,
12575                        reversed: selection.reversed,
12576                    });
12577                }
12578            }
12579            None
12580        }
12581
12582        let mut selected_larger_symbol = false;
12583        let new_selections = old_selections
12584            .iter()
12585            .map(|selection| match update_selection(selection, &buffer) {
12586                Some(new_selection) => {
12587                    if new_selection.range() != selection.range() {
12588                        selected_larger_symbol = true;
12589                    }
12590                    new_selection
12591                }
12592                None => selection.clone(),
12593            })
12594            .collect::<Vec<_>>();
12595
12596        if selected_larger_symbol {
12597            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12598                s.select(new_selections);
12599            });
12600        }
12601    }
12602
12603    pub fn select_larger_syntax_node(
12604        &mut self,
12605        _: &SelectLargerSyntaxNode,
12606        window: &mut Window,
12607        cx: &mut Context<Self>,
12608    ) {
12609        let Some(visible_row_count) = self.visible_row_count() else {
12610            return;
12611        };
12612        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
12613        if old_selections.is_empty() {
12614            return;
12615        }
12616
12617        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12618
12619        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12620        let buffer = self.buffer.read(cx).snapshot(cx);
12621
12622        let mut selected_larger_node = false;
12623        let mut new_selections = old_selections
12624            .iter()
12625            .map(|selection| {
12626                let old_range = selection.start..selection.end;
12627
12628                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
12629                    // manually select word at selection
12630                    if ["string_content", "inline"].contains(&node.kind()) {
12631                        let word_range = {
12632                            let display_point = buffer
12633                                .offset_to_point(old_range.start)
12634                                .to_display_point(&display_map);
12635                            let Range { start, end } =
12636                                movement::surrounding_word(&display_map, display_point);
12637                            start.to_point(&display_map).to_offset(&buffer)
12638                                ..end.to_point(&display_map).to_offset(&buffer)
12639                        };
12640                        // ignore if word is already selected
12641                        if !word_range.is_empty() && old_range != word_range {
12642                            let last_word_range = {
12643                                let display_point = buffer
12644                                    .offset_to_point(old_range.end)
12645                                    .to_display_point(&display_map);
12646                                let Range { start, end } =
12647                                    movement::surrounding_word(&display_map, display_point);
12648                                start.to_point(&display_map).to_offset(&buffer)
12649                                    ..end.to_point(&display_map).to_offset(&buffer)
12650                            };
12651                            // only select word if start and end point belongs to same word
12652                            if word_range == last_word_range {
12653                                selected_larger_node = true;
12654                                return Selection {
12655                                    id: selection.id,
12656                                    start: word_range.start,
12657                                    end: word_range.end,
12658                                    goal: SelectionGoal::None,
12659                                    reversed: selection.reversed,
12660                                };
12661                            }
12662                        }
12663                    }
12664                }
12665
12666                let mut new_range = old_range.clone();
12667                let mut new_node = None;
12668                while let Some((node, containing_range)) = buffer.syntax_ancestor(new_range.clone())
12669                {
12670                    new_node = Some(node);
12671                    new_range = match containing_range {
12672                        MultiOrSingleBufferOffsetRange::Single(_) => break,
12673                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
12674                    };
12675                    if !display_map.intersects_fold(new_range.start)
12676                        && !display_map.intersects_fold(new_range.end)
12677                    {
12678                        break;
12679                    }
12680                }
12681
12682                if let Some(node) = new_node {
12683                    // Log the ancestor, to support using this action as a way to explore TreeSitter
12684                    // nodes. Parent and grandparent are also logged because this operation will not
12685                    // visit nodes that have the same range as their parent.
12686                    log::info!("Node: {node:?}");
12687                    let parent = node.parent();
12688                    log::info!("Parent: {parent:?}");
12689                    let grandparent = parent.and_then(|x| x.parent());
12690                    log::info!("Grandparent: {grandparent:?}");
12691                }
12692
12693                selected_larger_node |= new_range != old_range;
12694                Selection {
12695                    id: selection.id,
12696                    start: new_range.start,
12697                    end: new_range.end,
12698                    goal: SelectionGoal::None,
12699                    reversed: selection.reversed,
12700                }
12701            })
12702            .collect::<Vec<_>>();
12703
12704        if !selected_larger_node {
12705            return; // don't put this call in the history
12706        }
12707
12708        // scroll based on transformation done to the last selection created by the user
12709        let (last_old, last_new) = old_selections
12710            .last()
12711            .zip(new_selections.last().cloned())
12712            .expect("old_selections isn't empty");
12713
12714        // revert selection
12715        let is_selection_reversed = {
12716            let should_newest_selection_be_reversed = last_old.start != last_new.start;
12717            new_selections.last_mut().expect("checked above").reversed =
12718                should_newest_selection_be_reversed;
12719            should_newest_selection_be_reversed
12720        };
12721
12722        if selected_larger_node {
12723            self.select_syntax_node_history.disable_clearing = true;
12724            self.change_selections(None, window, cx, |s| {
12725                s.select(new_selections.clone());
12726            });
12727            self.select_syntax_node_history.disable_clearing = false;
12728        }
12729
12730        let start_row = last_new.start.to_display_point(&display_map).row().0;
12731        let end_row = last_new.end.to_display_point(&display_map).row().0;
12732        let selection_height = end_row - start_row + 1;
12733        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
12734
12735        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
12736        let scroll_behavior = if fits_on_the_screen {
12737            self.request_autoscroll(Autoscroll::fit(), cx);
12738            SelectSyntaxNodeScrollBehavior::FitSelection
12739        } else if is_selection_reversed {
12740            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
12741            SelectSyntaxNodeScrollBehavior::CursorTop
12742        } else {
12743            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
12744            SelectSyntaxNodeScrollBehavior::CursorBottom
12745        };
12746
12747        self.select_syntax_node_history.push((
12748            old_selections,
12749            scroll_behavior,
12750            is_selection_reversed,
12751        ));
12752    }
12753
12754    pub fn select_smaller_syntax_node(
12755        &mut self,
12756        _: &SelectSmallerSyntaxNode,
12757        window: &mut Window,
12758        cx: &mut Context<Self>,
12759    ) {
12760        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12761
12762        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
12763            self.select_syntax_node_history.pop()
12764        {
12765            if let Some(selection) = selections.last_mut() {
12766                selection.reversed = is_selection_reversed;
12767            }
12768
12769            self.select_syntax_node_history.disable_clearing = true;
12770            self.change_selections(None, window, cx, |s| {
12771                s.select(selections.to_vec());
12772            });
12773            self.select_syntax_node_history.disable_clearing = false;
12774
12775            match scroll_behavior {
12776                SelectSyntaxNodeScrollBehavior::CursorTop => {
12777                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
12778                }
12779                SelectSyntaxNodeScrollBehavior::FitSelection => {
12780                    self.request_autoscroll(Autoscroll::fit(), cx);
12781                }
12782                SelectSyntaxNodeScrollBehavior::CursorBottom => {
12783                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
12784                }
12785            }
12786        }
12787    }
12788
12789    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
12790        if !EditorSettings::get_global(cx).gutter.runnables {
12791            self.clear_tasks();
12792            return Task::ready(());
12793        }
12794        let project = self.project.as_ref().map(Entity::downgrade);
12795        let task_sources = self.lsp_task_sources(cx);
12796        cx.spawn_in(window, async move |editor, cx| {
12797            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
12798            let Some(project) = project.and_then(|p| p.upgrade()) else {
12799                return;
12800            };
12801            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
12802                this.display_map.update(cx, |map, cx| map.snapshot(cx))
12803            }) else {
12804                return;
12805            };
12806
12807            let hide_runnables = project
12808                .update(cx, |project, cx| {
12809                    // Do not display any test indicators in non-dev server remote projects.
12810                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
12811                })
12812                .unwrap_or(true);
12813            if hide_runnables {
12814                return;
12815            }
12816            let new_rows =
12817                cx.background_spawn({
12818                    let snapshot = display_snapshot.clone();
12819                    async move {
12820                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
12821                    }
12822                })
12823                    .await;
12824            let Ok(lsp_tasks) =
12825                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
12826            else {
12827                return;
12828            };
12829            let lsp_tasks = lsp_tasks.await;
12830
12831            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
12832                lsp_tasks
12833                    .into_iter()
12834                    .flat_map(|(kind, tasks)| {
12835                        tasks.into_iter().filter_map(move |(location, task)| {
12836                            Some((kind.clone(), location?, task))
12837                        })
12838                    })
12839                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
12840                        let buffer = location.target.buffer;
12841                        let buffer_snapshot = buffer.read(cx).snapshot();
12842                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
12843                            |(excerpt_id, snapshot, _)| {
12844                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
12845                                    display_snapshot
12846                                        .buffer_snapshot
12847                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
12848                                } else {
12849                                    None
12850                                }
12851                            },
12852                        );
12853                        if let Some(offset) = offset {
12854                            let task_buffer_range =
12855                                location.target.range.to_point(&buffer_snapshot);
12856                            let context_buffer_range =
12857                                task_buffer_range.to_offset(&buffer_snapshot);
12858                            let context_range = BufferOffset(context_buffer_range.start)
12859                                ..BufferOffset(context_buffer_range.end);
12860
12861                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
12862                                .or_insert_with(|| RunnableTasks {
12863                                    templates: Vec::new(),
12864                                    offset,
12865                                    column: task_buffer_range.start.column,
12866                                    extra_variables: HashMap::default(),
12867                                    context_range,
12868                                })
12869                                .templates
12870                                .push((kind, task.original_task().clone()));
12871                        }
12872
12873                        acc
12874                    })
12875            }) else {
12876                return;
12877            };
12878
12879            let rows = Self::runnable_rows(project, display_snapshot, new_rows, cx.clone());
12880            editor
12881                .update(cx, |editor, _| {
12882                    editor.clear_tasks();
12883                    for (key, mut value) in rows {
12884                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
12885                            value.templates.extend(lsp_tasks.templates);
12886                        }
12887
12888                        editor.insert_tasks(key, value);
12889                    }
12890                    for (key, value) in lsp_tasks_by_rows {
12891                        editor.insert_tasks(key, value);
12892                    }
12893                })
12894                .ok();
12895        })
12896    }
12897    fn fetch_runnable_ranges(
12898        snapshot: &DisplaySnapshot,
12899        range: Range<Anchor>,
12900    ) -> Vec<language::RunnableRange> {
12901        snapshot.buffer_snapshot.runnable_ranges(range).collect()
12902    }
12903
12904    fn runnable_rows(
12905        project: Entity<Project>,
12906        snapshot: DisplaySnapshot,
12907        runnable_ranges: Vec<RunnableRange>,
12908        mut cx: AsyncWindowContext,
12909    ) -> Vec<((BufferId, BufferRow), RunnableTasks)> {
12910        runnable_ranges
12911            .into_iter()
12912            .filter_map(|mut runnable| {
12913                let tasks = cx
12914                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
12915                    .ok()?;
12916                if tasks.is_empty() {
12917                    return None;
12918                }
12919
12920                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
12921
12922                let row = snapshot
12923                    .buffer_snapshot
12924                    .buffer_line_for_row(MultiBufferRow(point.row))?
12925                    .1
12926                    .start
12927                    .row;
12928
12929                let context_range =
12930                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
12931                Some((
12932                    (runnable.buffer_id, row),
12933                    RunnableTasks {
12934                        templates: tasks,
12935                        offset: snapshot
12936                            .buffer_snapshot
12937                            .anchor_before(runnable.run_range.start),
12938                        context_range,
12939                        column: point.column,
12940                        extra_variables: runnable.extra_captures,
12941                    },
12942                ))
12943            })
12944            .collect()
12945    }
12946
12947    fn templates_with_tags(
12948        project: &Entity<Project>,
12949        runnable: &mut Runnable,
12950        cx: &mut App,
12951    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
12952        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
12953            let (worktree_id, file) = project
12954                .buffer_for_id(runnable.buffer, cx)
12955                .and_then(|buffer| buffer.read(cx).file())
12956                .map(|file| (file.worktree_id(cx), file.clone()))
12957                .unzip();
12958
12959            (
12960                project.task_store().read(cx).task_inventory().cloned(),
12961                worktree_id,
12962                file,
12963            )
12964        });
12965
12966        let mut templates_with_tags = mem::take(&mut runnable.tags)
12967            .into_iter()
12968            .flat_map(|RunnableTag(tag)| {
12969                inventory
12970                    .as_ref()
12971                    .into_iter()
12972                    .flat_map(|inventory| {
12973                        inventory.read(cx).list_tasks(
12974                            file.clone(),
12975                            Some(runnable.language.clone()),
12976                            worktree_id,
12977                            cx,
12978                        )
12979                    })
12980                    .filter(move |(_, template)| {
12981                        template.tags.iter().any(|source_tag| source_tag == &tag)
12982                    })
12983            })
12984            .sorted_by_key(|(kind, _)| kind.to_owned())
12985            .collect::<Vec<_>>();
12986        if let Some((leading_tag_source, _)) = templates_with_tags.first() {
12987            // Strongest source wins; if we have worktree tag binding, prefer that to
12988            // global and language bindings;
12989            // if we have a global binding, prefer that to language binding.
12990            let first_mismatch = templates_with_tags
12991                .iter()
12992                .position(|(tag_source, _)| tag_source != leading_tag_source);
12993            if let Some(index) = first_mismatch {
12994                templates_with_tags.truncate(index);
12995            }
12996        }
12997
12998        templates_with_tags
12999    }
13000
13001    pub fn move_to_enclosing_bracket(
13002        &mut self,
13003        _: &MoveToEnclosingBracket,
13004        window: &mut Window,
13005        cx: &mut Context<Self>,
13006    ) {
13007        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13008        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13009            s.move_offsets_with(|snapshot, selection| {
13010                let Some(enclosing_bracket_ranges) =
13011                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
13012                else {
13013                    return;
13014                };
13015
13016                let mut best_length = usize::MAX;
13017                let mut best_inside = false;
13018                let mut best_in_bracket_range = false;
13019                let mut best_destination = None;
13020                for (open, close) in enclosing_bracket_ranges {
13021                    let close = close.to_inclusive();
13022                    let length = close.end() - open.start;
13023                    let inside = selection.start >= open.end && selection.end <= *close.start();
13024                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
13025                        || close.contains(&selection.head());
13026
13027                    // If best is next to a bracket and current isn't, skip
13028                    if !in_bracket_range && best_in_bracket_range {
13029                        continue;
13030                    }
13031
13032                    // Prefer smaller lengths unless best is inside and current isn't
13033                    if length > best_length && (best_inside || !inside) {
13034                        continue;
13035                    }
13036
13037                    best_length = length;
13038                    best_inside = inside;
13039                    best_in_bracket_range = in_bracket_range;
13040                    best_destination = Some(
13041                        if close.contains(&selection.start) && close.contains(&selection.end) {
13042                            if inside { open.end } else { open.start }
13043                        } else if inside {
13044                            *close.start()
13045                        } else {
13046                            *close.end()
13047                        },
13048                    );
13049                }
13050
13051                if let Some(destination) = best_destination {
13052                    selection.collapse_to(destination, SelectionGoal::None);
13053                }
13054            })
13055        });
13056    }
13057
13058    pub fn undo_selection(
13059        &mut self,
13060        _: &UndoSelection,
13061        window: &mut Window,
13062        cx: &mut Context<Self>,
13063    ) {
13064        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13065        self.end_selection(window, cx);
13066        self.selection_history.mode = SelectionHistoryMode::Undoing;
13067        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
13068            self.change_selections(None, window, cx, |s| {
13069                s.select_anchors(entry.selections.to_vec())
13070            });
13071            self.select_next_state = entry.select_next_state;
13072            self.select_prev_state = entry.select_prev_state;
13073            self.add_selections_state = entry.add_selections_state;
13074            self.request_autoscroll(Autoscroll::newest(), cx);
13075        }
13076        self.selection_history.mode = SelectionHistoryMode::Normal;
13077    }
13078
13079    pub fn redo_selection(
13080        &mut self,
13081        _: &RedoSelection,
13082        window: &mut Window,
13083        cx: &mut Context<Self>,
13084    ) {
13085        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13086        self.end_selection(window, cx);
13087        self.selection_history.mode = SelectionHistoryMode::Redoing;
13088        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
13089            self.change_selections(None, window, cx, |s| {
13090                s.select_anchors(entry.selections.to_vec())
13091            });
13092            self.select_next_state = entry.select_next_state;
13093            self.select_prev_state = entry.select_prev_state;
13094            self.add_selections_state = entry.add_selections_state;
13095            self.request_autoscroll(Autoscroll::newest(), cx);
13096        }
13097        self.selection_history.mode = SelectionHistoryMode::Normal;
13098    }
13099
13100    pub fn expand_excerpts(
13101        &mut self,
13102        action: &ExpandExcerpts,
13103        _: &mut Window,
13104        cx: &mut Context<Self>,
13105    ) {
13106        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
13107    }
13108
13109    pub fn expand_excerpts_down(
13110        &mut self,
13111        action: &ExpandExcerptsDown,
13112        _: &mut Window,
13113        cx: &mut Context<Self>,
13114    ) {
13115        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
13116    }
13117
13118    pub fn expand_excerpts_up(
13119        &mut self,
13120        action: &ExpandExcerptsUp,
13121        _: &mut Window,
13122        cx: &mut Context<Self>,
13123    ) {
13124        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
13125    }
13126
13127    pub fn expand_excerpts_for_direction(
13128        &mut self,
13129        lines: u32,
13130        direction: ExpandExcerptDirection,
13131
13132        cx: &mut Context<Self>,
13133    ) {
13134        let selections = self.selections.disjoint_anchors();
13135
13136        let lines = if lines == 0 {
13137            EditorSettings::get_global(cx).expand_excerpt_lines
13138        } else {
13139            lines
13140        };
13141
13142        self.buffer.update(cx, |buffer, cx| {
13143            let snapshot = buffer.snapshot(cx);
13144            let mut excerpt_ids = selections
13145                .iter()
13146                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
13147                .collect::<Vec<_>>();
13148            excerpt_ids.sort();
13149            excerpt_ids.dedup();
13150            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
13151        })
13152    }
13153
13154    pub fn expand_excerpt(
13155        &mut self,
13156        excerpt: ExcerptId,
13157        direction: ExpandExcerptDirection,
13158        window: &mut Window,
13159        cx: &mut Context<Self>,
13160    ) {
13161        let current_scroll_position = self.scroll_position(cx);
13162        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
13163        let mut should_scroll_up = false;
13164
13165        if direction == ExpandExcerptDirection::Down {
13166            let multi_buffer = self.buffer.read(cx);
13167            let snapshot = multi_buffer.snapshot(cx);
13168            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
13169                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
13170                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
13171                        let buffer_snapshot = buffer.read(cx).snapshot();
13172                        let excerpt_end_row =
13173                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
13174                        let last_row = buffer_snapshot.max_point().row;
13175                        let lines_below = last_row.saturating_sub(excerpt_end_row);
13176                        should_scroll_up = lines_below >= lines_to_expand;
13177                    }
13178                }
13179            }
13180        }
13181
13182        self.buffer.update(cx, |buffer, cx| {
13183            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
13184        });
13185
13186        if should_scroll_up {
13187            let new_scroll_position =
13188                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
13189            self.set_scroll_position(new_scroll_position, window, cx);
13190        }
13191    }
13192
13193    pub fn go_to_singleton_buffer_point(
13194        &mut self,
13195        point: Point,
13196        window: &mut Window,
13197        cx: &mut Context<Self>,
13198    ) {
13199        self.go_to_singleton_buffer_range(point..point, window, cx);
13200    }
13201
13202    pub fn go_to_singleton_buffer_range(
13203        &mut self,
13204        range: Range<Point>,
13205        window: &mut Window,
13206        cx: &mut Context<Self>,
13207    ) {
13208        let multibuffer = self.buffer().read(cx);
13209        let Some(buffer) = multibuffer.as_singleton() else {
13210            return;
13211        };
13212        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
13213            return;
13214        };
13215        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
13216            return;
13217        };
13218        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
13219            s.select_anchor_ranges([start..end])
13220        });
13221    }
13222
13223    pub fn go_to_diagnostic(
13224        &mut self,
13225        _: &GoToDiagnostic,
13226        window: &mut Window,
13227        cx: &mut Context<Self>,
13228    ) {
13229        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13230        self.go_to_diagnostic_impl(Direction::Next, window, cx)
13231    }
13232
13233    pub fn go_to_prev_diagnostic(
13234        &mut self,
13235        _: &GoToPreviousDiagnostic,
13236        window: &mut Window,
13237        cx: &mut Context<Self>,
13238    ) {
13239        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13240        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
13241    }
13242
13243    pub fn go_to_diagnostic_impl(
13244        &mut self,
13245        direction: Direction,
13246        window: &mut Window,
13247        cx: &mut Context<Self>,
13248    ) {
13249        let buffer = self.buffer.read(cx).snapshot(cx);
13250        let selection = self.selections.newest::<usize>(cx);
13251
13252        let mut active_group_id = None;
13253        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
13254            if active_group.active_range.start.to_offset(&buffer) == selection.start {
13255                active_group_id = Some(active_group.group_id);
13256            }
13257        }
13258
13259        fn filtered(
13260            snapshot: EditorSnapshot,
13261            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
13262        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
13263            diagnostics
13264                .filter(|entry| entry.range.start != entry.range.end)
13265                .filter(|entry| !entry.diagnostic.is_unnecessary)
13266                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
13267        }
13268
13269        let snapshot = self.snapshot(window, cx);
13270        let before = filtered(
13271            snapshot.clone(),
13272            buffer
13273                .diagnostics_in_range(0..selection.start)
13274                .filter(|entry| entry.range.start <= selection.start),
13275        );
13276        let after = filtered(
13277            snapshot,
13278            buffer
13279                .diagnostics_in_range(selection.start..buffer.len())
13280                .filter(|entry| entry.range.start >= selection.start),
13281        );
13282
13283        let mut found: Option<DiagnosticEntry<usize>> = None;
13284        if direction == Direction::Prev {
13285            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
13286            {
13287                for diagnostic in prev_diagnostics.into_iter().rev() {
13288                    if diagnostic.range.start != selection.start
13289                        || active_group_id
13290                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
13291                    {
13292                        found = Some(diagnostic);
13293                        break 'outer;
13294                    }
13295                }
13296            }
13297        } else {
13298            for diagnostic in after.chain(before) {
13299                if diagnostic.range.start != selection.start
13300                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
13301                {
13302                    found = Some(diagnostic);
13303                    break;
13304                }
13305            }
13306        }
13307        let Some(next_diagnostic) = found else {
13308            return;
13309        };
13310
13311        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
13312            return;
13313        };
13314        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13315            s.select_ranges(vec![
13316                next_diagnostic.range.start..next_diagnostic.range.start,
13317            ])
13318        });
13319        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
13320        self.refresh_inline_completion(false, true, window, cx);
13321    }
13322
13323    fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
13324        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13325        let snapshot = self.snapshot(window, cx);
13326        let selection = self.selections.newest::<Point>(cx);
13327        self.go_to_hunk_before_or_after_position(
13328            &snapshot,
13329            selection.head(),
13330            Direction::Next,
13331            window,
13332            cx,
13333        );
13334    }
13335
13336    pub fn go_to_hunk_before_or_after_position(
13337        &mut self,
13338        snapshot: &EditorSnapshot,
13339        position: Point,
13340        direction: Direction,
13341        window: &mut Window,
13342        cx: &mut Context<Editor>,
13343    ) {
13344        let row = if direction == Direction::Next {
13345            self.hunk_after_position(snapshot, position)
13346                .map(|hunk| hunk.row_range.start)
13347        } else {
13348            self.hunk_before_position(snapshot, position)
13349        };
13350
13351        if let Some(row) = row {
13352            let destination = Point::new(row.0, 0);
13353            let autoscroll = Autoscroll::center();
13354
13355            self.unfold_ranges(&[destination..destination], false, false, cx);
13356            self.change_selections(Some(autoscroll), window, cx, |s| {
13357                s.select_ranges([destination..destination]);
13358            });
13359        }
13360    }
13361
13362    fn hunk_after_position(
13363        &mut self,
13364        snapshot: &EditorSnapshot,
13365        position: Point,
13366    ) -> Option<MultiBufferDiffHunk> {
13367        snapshot
13368            .buffer_snapshot
13369            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
13370            .find(|hunk| hunk.row_range.start.0 > position.row)
13371            .or_else(|| {
13372                snapshot
13373                    .buffer_snapshot
13374                    .diff_hunks_in_range(Point::zero()..position)
13375                    .find(|hunk| hunk.row_range.end.0 < position.row)
13376            })
13377    }
13378
13379    fn go_to_prev_hunk(
13380        &mut self,
13381        _: &GoToPreviousHunk,
13382        window: &mut Window,
13383        cx: &mut Context<Self>,
13384    ) {
13385        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13386        let snapshot = self.snapshot(window, cx);
13387        let selection = self.selections.newest::<Point>(cx);
13388        self.go_to_hunk_before_or_after_position(
13389            &snapshot,
13390            selection.head(),
13391            Direction::Prev,
13392            window,
13393            cx,
13394        );
13395    }
13396
13397    fn hunk_before_position(
13398        &mut self,
13399        snapshot: &EditorSnapshot,
13400        position: Point,
13401    ) -> Option<MultiBufferRow> {
13402        snapshot
13403            .buffer_snapshot
13404            .diff_hunk_before(position)
13405            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
13406    }
13407
13408    fn go_to_next_change(
13409        &mut self,
13410        _: &GoToNextChange,
13411        window: &mut Window,
13412        cx: &mut Context<Self>,
13413    ) {
13414        if let Some(selections) = self
13415            .change_list
13416            .next_change(1, Direction::Next)
13417            .map(|s| s.to_vec())
13418        {
13419            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13420                let map = s.display_map();
13421                s.select_display_ranges(selections.iter().map(|a| {
13422                    let point = a.to_display_point(&map);
13423                    point..point
13424                }))
13425            })
13426        }
13427    }
13428
13429    fn go_to_previous_change(
13430        &mut self,
13431        _: &GoToPreviousChange,
13432        window: &mut Window,
13433        cx: &mut Context<Self>,
13434    ) {
13435        if let Some(selections) = self
13436            .change_list
13437            .next_change(1, Direction::Prev)
13438            .map(|s| s.to_vec())
13439        {
13440            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13441                let map = s.display_map();
13442                s.select_display_ranges(selections.iter().map(|a| {
13443                    let point = a.to_display_point(&map);
13444                    point..point
13445                }))
13446            })
13447        }
13448    }
13449
13450    fn go_to_line<T: 'static>(
13451        &mut self,
13452        position: Anchor,
13453        highlight_color: Option<Hsla>,
13454        window: &mut Window,
13455        cx: &mut Context<Self>,
13456    ) {
13457        let snapshot = self.snapshot(window, cx).display_snapshot;
13458        let position = position.to_point(&snapshot.buffer_snapshot);
13459        let start = snapshot
13460            .buffer_snapshot
13461            .clip_point(Point::new(position.row, 0), Bias::Left);
13462        let end = start + Point::new(1, 0);
13463        let start = snapshot.buffer_snapshot.anchor_before(start);
13464        let end = snapshot.buffer_snapshot.anchor_before(end);
13465
13466        self.highlight_rows::<T>(
13467            start..end,
13468            highlight_color
13469                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
13470            false,
13471            cx,
13472        );
13473        self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
13474    }
13475
13476    pub fn go_to_definition(
13477        &mut self,
13478        _: &GoToDefinition,
13479        window: &mut Window,
13480        cx: &mut Context<Self>,
13481    ) -> Task<Result<Navigated>> {
13482        let definition =
13483            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
13484        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
13485        cx.spawn_in(window, async move |editor, cx| {
13486            if definition.await? == Navigated::Yes {
13487                return Ok(Navigated::Yes);
13488            }
13489            match fallback_strategy {
13490                GoToDefinitionFallback::None => Ok(Navigated::No),
13491                GoToDefinitionFallback::FindAllReferences => {
13492                    match editor.update_in(cx, |editor, window, cx| {
13493                        editor.find_all_references(&FindAllReferences, window, cx)
13494                    })? {
13495                        Some(references) => references.await,
13496                        None => Ok(Navigated::No),
13497                    }
13498                }
13499            }
13500        })
13501    }
13502
13503    pub fn go_to_declaration(
13504        &mut self,
13505        _: &GoToDeclaration,
13506        window: &mut Window,
13507        cx: &mut Context<Self>,
13508    ) -> Task<Result<Navigated>> {
13509        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
13510    }
13511
13512    pub fn go_to_declaration_split(
13513        &mut self,
13514        _: &GoToDeclaration,
13515        window: &mut Window,
13516        cx: &mut Context<Self>,
13517    ) -> Task<Result<Navigated>> {
13518        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
13519    }
13520
13521    pub fn go_to_implementation(
13522        &mut self,
13523        _: &GoToImplementation,
13524        window: &mut Window,
13525        cx: &mut Context<Self>,
13526    ) -> Task<Result<Navigated>> {
13527        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
13528    }
13529
13530    pub fn go_to_implementation_split(
13531        &mut self,
13532        _: &GoToImplementationSplit,
13533        window: &mut Window,
13534        cx: &mut Context<Self>,
13535    ) -> Task<Result<Navigated>> {
13536        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
13537    }
13538
13539    pub fn go_to_type_definition(
13540        &mut self,
13541        _: &GoToTypeDefinition,
13542        window: &mut Window,
13543        cx: &mut Context<Self>,
13544    ) -> Task<Result<Navigated>> {
13545        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
13546    }
13547
13548    pub fn go_to_definition_split(
13549        &mut self,
13550        _: &GoToDefinitionSplit,
13551        window: &mut Window,
13552        cx: &mut Context<Self>,
13553    ) -> Task<Result<Navigated>> {
13554        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
13555    }
13556
13557    pub fn go_to_type_definition_split(
13558        &mut self,
13559        _: &GoToTypeDefinitionSplit,
13560        window: &mut Window,
13561        cx: &mut Context<Self>,
13562    ) -> Task<Result<Navigated>> {
13563        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
13564    }
13565
13566    fn go_to_definition_of_kind(
13567        &mut self,
13568        kind: GotoDefinitionKind,
13569        split: bool,
13570        window: &mut Window,
13571        cx: &mut Context<Self>,
13572    ) -> Task<Result<Navigated>> {
13573        let Some(provider) = self.semantics_provider.clone() else {
13574            return Task::ready(Ok(Navigated::No));
13575        };
13576        let head = self.selections.newest::<usize>(cx).head();
13577        let buffer = self.buffer.read(cx);
13578        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
13579            text_anchor
13580        } else {
13581            return Task::ready(Ok(Navigated::No));
13582        };
13583
13584        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
13585            return Task::ready(Ok(Navigated::No));
13586        };
13587
13588        cx.spawn_in(window, async move |editor, cx| {
13589            let definitions = definitions.await?;
13590            let navigated = editor
13591                .update_in(cx, |editor, window, cx| {
13592                    editor.navigate_to_hover_links(
13593                        Some(kind),
13594                        definitions
13595                            .into_iter()
13596                            .filter(|location| {
13597                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
13598                            })
13599                            .map(HoverLink::Text)
13600                            .collect::<Vec<_>>(),
13601                        split,
13602                        window,
13603                        cx,
13604                    )
13605                })?
13606                .await?;
13607            anyhow::Ok(navigated)
13608        })
13609    }
13610
13611    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
13612        let selection = self.selections.newest_anchor();
13613        let head = selection.head();
13614        let tail = selection.tail();
13615
13616        let Some((buffer, start_position)) =
13617            self.buffer.read(cx).text_anchor_for_position(head, cx)
13618        else {
13619            return;
13620        };
13621
13622        let end_position = if head != tail {
13623            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
13624                return;
13625            };
13626            Some(pos)
13627        } else {
13628            None
13629        };
13630
13631        let url_finder = cx.spawn_in(window, async move |editor, cx| {
13632            let url = if let Some(end_pos) = end_position {
13633                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
13634            } else {
13635                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
13636            };
13637
13638            if let Some(url) = url {
13639                editor.update(cx, |_, cx| {
13640                    cx.open_url(&url);
13641                })
13642            } else {
13643                Ok(())
13644            }
13645        });
13646
13647        url_finder.detach();
13648    }
13649
13650    pub fn open_selected_filename(
13651        &mut self,
13652        _: &OpenSelectedFilename,
13653        window: &mut Window,
13654        cx: &mut Context<Self>,
13655    ) {
13656        let Some(workspace) = self.workspace() else {
13657            return;
13658        };
13659
13660        let position = self.selections.newest_anchor().head();
13661
13662        let Some((buffer, buffer_position)) =
13663            self.buffer.read(cx).text_anchor_for_position(position, cx)
13664        else {
13665            return;
13666        };
13667
13668        let project = self.project.clone();
13669
13670        cx.spawn_in(window, async move |_, cx| {
13671            let result = find_file(&buffer, project, buffer_position, cx).await;
13672
13673            if let Some((_, path)) = result {
13674                workspace
13675                    .update_in(cx, |workspace, window, cx| {
13676                        workspace.open_resolved_path(path, window, cx)
13677                    })?
13678                    .await?;
13679            }
13680            anyhow::Ok(())
13681        })
13682        .detach();
13683    }
13684
13685    pub(crate) fn navigate_to_hover_links(
13686        &mut self,
13687        kind: Option<GotoDefinitionKind>,
13688        mut definitions: Vec<HoverLink>,
13689        split: bool,
13690        window: &mut Window,
13691        cx: &mut Context<Editor>,
13692    ) -> Task<Result<Navigated>> {
13693        // If there is one definition, just open it directly
13694        if definitions.len() == 1 {
13695            let definition = definitions.pop().unwrap();
13696
13697            enum TargetTaskResult {
13698                Location(Option<Location>),
13699                AlreadyNavigated,
13700            }
13701
13702            let target_task = match definition {
13703                HoverLink::Text(link) => {
13704                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
13705                }
13706                HoverLink::InlayHint(lsp_location, server_id) => {
13707                    let computation =
13708                        self.compute_target_location(lsp_location, server_id, window, cx);
13709                    cx.background_spawn(async move {
13710                        let location = computation.await?;
13711                        Ok(TargetTaskResult::Location(location))
13712                    })
13713                }
13714                HoverLink::Url(url) => {
13715                    cx.open_url(&url);
13716                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
13717                }
13718                HoverLink::File(path) => {
13719                    if let Some(workspace) = self.workspace() {
13720                        cx.spawn_in(window, async move |_, cx| {
13721                            workspace
13722                                .update_in(cx, |workspace, window, cx| {
13723                                    workspace.open_resolved_path(path, window, cx)
13724                                })?
13725                                .await
13726                                .map(|_| TargetTaskResult::AlreadyNavigated)
13727                        })
13728                    } else {
13729                        Task::ready(Ok(TargetTaskResult::Location(None)))
13730                    }
13731                }
13732            };
13733            cx.spawn_in(window, async move |editor, cx| {
13734                let target = match target_task.await.context("target resolution task")? {
13735                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
13736                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
13737                    TargetTaskResult::Location(Some(target)) => target,
13738                };
13739
13740                editor.update_in(cx, |editor, window, cx| {
13741                    let Some(workspace) = editor.workspace() else {
13742                        return Navigated::No;
13743                    };
13744                    let pane = workspace.read(cx).active_pane().clone();
13745
13746                    let range = target.range.to_point(target.buffer.read(cx));
13747                    let range = editor.range_for_match(&range);
13748                    let range = collapse_multiline_range(range);
13749
13750                    if !split
13751                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
13752                    {
13753                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
13754                    } else {
13755                        window.defer(cx, move |window, cx| {
13756                            let target_editor: Entity<Self> =
13757                                workspace.update(cx, |workspace, cx| {
13758                                    let pane = if split {
13759                                        workspace.adjacent_pane(window, cx)
13760                                    } else {
13761                                        workspace.active_pane().clone()
13762                                    };
13763
13764                                    workspace.open_project_item(
13765                                        pane,
13766                                        target.buffer.clone(),
13767                                        true,
13768                                        true,
13769                                        window,
13770                                        cx,
13771                                    )
13772                                });
13773                            target_editor.update(cx, |target_editor, cx| {
13774                                // When selecting a definition in a different buffer, disable the nav history
13775                                // to avoid creating a history entry at the previous cursor location.
13776                                pane.update(cx, |pane, _| pane.disable_history());
13777                                target_editor.go_to_singleton_buffer_range(range, window, cx);
13778                                pane.update(cx, |pane, _| pane.enable_history());
13779                            });
13780                        });
13781                    }
13782                    Navigated::Yes
13783                })
13784            })
13785        } else if !definitions.is_empty() {
13786            cx.spawn_in(window, async move |editor, cx| {
13787                let (title, location_tasks, workspace) = editor
13788                    .update_in(cx, |editor, window, cx| {
13789                        let tab_kind = match kind {
13790                            Some(GotoDefinitionKind::Implementation) => "Implementations",
13791                            _ => "Definitions",
13792                        };
13793                        let title = definitions
13794                            .iter()
13795                            .find_map(|definition| match definition {
13796                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
13797                                    let buffer = origin.buffer.read(cx);
13798                                    format!(
13799                                        "{} for {}",
13800                                        tab_kind,
13801                                        buffer
13802                                            .text_for_range(origin.range.clone())
13803                                            .collect::<String>()
13804                                    )
13805                                }),
13806                                HoverLink::InlayHint(_, _) => None,
13807                                HoverLink::Url(_) => None,
13808                                HoverLink::File(_) => None,
13809                            })
13810                            .unwrap_or(tab_kind.to_string());
13811                        let location_tasks = definitions
13812                            .into_iter()
13813                            .map(|definition| match definition {
13814                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
13815                                HoverLink::InlayHint(lsp_location, server_id) => editor
13816                                    .compute_target_location(lsp_location, server_id, window, cx),
13817                                HoverLink::Url(_) => Task::ready(Ok(None)),
13818                                HoverLink::File(_) => Task::ready(Ok(None)),
13819                            })
13820                            .collect::<Vec<_>>();
13821                        (title, location_tasks, editor.workspace().clone())
13822                    })
13823                    .context("location tasks preparation")?;
13824
13825                let locations = future::join_all(location_tasks)
13826                    .await
13827                    .into_iter()
13828                    .filter_map(|location| location.transpose())
13829                    .collect::<Result<_>>()
13830                    .context("location tasks")?;
13831
13832                let Some(workspace) = workspace else {
13833                    return Ok(Navigated::No);
13834                };
13835                let opened = workspace
13836                    .update_in(cx, |workspace, window, cx| {
13837                        Self::open_locations_in_multibuffer(
13838                            workspace,
13839                            locations,
13840                            title,
13841                            split,
13842                            MultibufferSelectionMode::First,
13843                            window,
13844                            cx,
13845                        )
13846                    })
13847                    .ok();
13848
13849                anyhow::Ok(Navigated::from_bool(opened.is_some()))
13850            })
13851        } else {
13852            Task::ready(Ok(Navigated::No))
13853        }
13854    }
13855
13856    fn compute_target_location(
13857        &self,
13858        lsp_location: lsp::Location,
13859        server_id: LanguageServerId,
13860        window: &mut Window,
13861        cx: &mut Context<Self>,
13862    ) -> Task<anyhow::Result<Option<Location>>> {
13863        let Some(project) = self.project.clone() else {
13864            return Task::ready(Ok(None));
13865        };
13866
13867        cx.spawn_in(window, async move |editor, cx| {
13868            let location_task = editor.update(cx, |_, cx| {
13869                project.update(cx, |project, cx| {
13870                    let language_server_name = project
13871                        .language_server_statuses(cx)
13872                        .find(|(id, _)| server_id == *id)
13873                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
13874                    language_server_name.map(|language_server_name| {
13875                        project.open_local_buffer_via_lsp(
13876                            lsp_location.uri.clone(),
13877                            server_id,
13878                            language_server_name,
13879                            cx,
13880                        )
13881                    })
13882                })
13883            })?;
13884            let location = match location_task {
13885                Some(task) => Some({
13886                    let target_buffer_handle = task.await.context("open local buffer")?;
13887                    let range = target_buffer_handle.update(cx, |target_buffer, _| {
13888                        let target_start = target_buffer
13889                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
13890                        let target_end = target_buffer
13891                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
13892                        target_buffer.anchor_after(target_start)
13893                            ..target_buffer.anchor_before(target_end)
13894                    })?;
13895                    Location {
13896                        buffer: target_buffer_handle,
13897                        range,
13898                    }
13899                }),
13900                None => None,
13901            };
13902            Ok(location)
13903        })
13904    }
13905
13906    pub fn find_all_references(
13907        &mut self,
13908        _: &FindAllReferences,
13909        window: &mut Window,
13910        cx: &mut Context<Self>,
13911    ) -> Option<Task<Result<Navigated>>> {
13912        let selection = self.selections.newest::<usize>(cx);
13913        let multi_buffer = self.buffer.read(cx);
13914        let head = selection.head();
13915
13916        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
13917        let head_anchor = multi_buffer_snapshot.anchor_at(
13918            head,
13919            if head < selection.tail() {
13920                Bias::Right
13921            } else {
13922                Bias::Left
13923            },
13924        );
13925
13926        match self
13927            .find_all_references_task_sources
13928            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
13929        {
13930            Ok(_) => {
13931                log::info!(
13932                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
13933                );
13934                return None;
13935            }
13936            Err(i) => {
13937                self.find_all_references_task_sources.insert(i, head_anchor);
13938            }
13939        }
13940
13941        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
13942        let workspace = self.workspace()?;
13943        let project = workspace.read(cx).project().clone();
13944        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
13945        Some(cx.spawn_in(window, async move |editor, cx| {
13946            let _cleanup = cx.on_drop(&editor, move |editor, _| {
13947                if let Ok(i) = editor
13948                    .find_all_references_task_sources
13949                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
13950                {
13951                    editor.find_all_references_task_sources.remove(i);
13952                }
13953            });
13954
13955            let locations = references.await?;
13956            if locations.is_empty() {
13957                return anyhow::Ok(Navigated::No);
13958            }
13959
13960            workspace.update_in(cx, |workspace, window, cx| {
13961                let title = locations
13962                    .first()
13963                    .as_ref()
13964                    .map(|location| {
13965                        let buffer = location.buffer.read(cx);
13966                        format!(
13967                            "References to `{}`",
13968                            buffer
13969                                .text_for_range(location.range.clone())
13970                                .collect::<String>()
13971                        )
13972                    })
13973                    .unwrap();
13974                Self::open_locations_in_multibuffer(
13975                    workspace,
13976                    locations,
13977                    title,
13978                    false,
13979                    MultibufferSelectionMode::First,
13980                    window,
13981                    cx,
13982                );
13983                Navigated::Yes
13984            })
13985        }))
13986    }
13987
13988    /// Opens a multibuffer with the given project locations in it
13989    pub fn open_locations_in_multibuffer(
13990        workspace: &mut Workspace,
13991        mut locations: Vec<Location>,
13992        title: String,
13993        split: bool,
13994        multibuffer_selection_mode: MultibufferSelectionMode,
13995        window: &mut Window,
13996        cx: &mut Context<Workspace>,
13997    ) {
13998        // If there are multiple definitions, open them in a multibuffer
13999        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
14000        let mut locations = locations.into_iter().peekable();
14001        let mut ranges: Vec<Range<Anchor>> = Vec::new();
14002        let capability = workspace.project().read(cx).capability();
14003
14004        let excerpt_buffer = cx.new(|cx| {
14005            let mut multibuffer = MultiBuffer::new(capability);
14006            while let Some(location) = locations.next() {
14007                let buffer = location.buffer.read(cx);
14008                let mut ranges_for_buffer = Vec::new();
14009                let range = location.range.to_point(buffer);
14010                ranges_for_buffer.push(range.clone());
14011
14012                while let Some(next_location) = locations.peek() {
14013                    if next_location.buffer == location.buffer {
14014                        ranges_for_buffer.push(next_location.range.to_point(buffer));
14015                        locations.next();
14016                    } else {
14017                        break;
14018                    }
14019                }
14020
14021                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
14022                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
14023                    PathKey::for_buffer(&location.buffer, cx),
14024                    location.buffer.clone(),
14025                    ranges_for_buffer,
14026                    DEFAULT_MULTIBUFFER_CONTEXT,
14027                    cx,
14028                );
14029                ranges.extend(new_ranges)
14030            }
14031
14032            multibuffer.with_title(title)
14033        });
14034
14035        let editor = cx.new(|cx| {
14036            Editor::for_multibuffer(
14037                excerpt_buffer,
14038                Some(workspace.project().clone()),
14039                window,
14040                cx,
14041            )
14042        });
14043        editor.update(cx, |editor, cx| {
14044            match multibuffer_selection_mode {
14045                MultibufferSelectionMode::First => {
14046                    if let Some(first_range) = ranges.first() {
14047                        editor.change_selections(None, window, cx, |selections| {
14048                            selections.clear_disjoint();
14049                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
14050                        });
14051                    }
14052                    editor.highlight_background::<Self>(
14053                        &ranges,
14054                        |theme| theme.editor_highlighted_line_background,
14055                        cx,
14056                    );
14057                }
14058                MultibufferSelectionMode::All => {
14059                    editor.change_selections(None, window, cx, |selections| {
14060                        selections.clear_disjoint();
14061                        selections.select_anchor_ranges(ranges);
14062                    });
14063                }
14064            }
14065            editor.register_buffers_with_language_servers(cx);
14066        });
14067
14068        let item = Box::new(editor);
14069        let item_id = item.item_id();
14070
14071        if split {
14072            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
14073        } else {
14074            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
14075                let (preview_item_id, preview_item_idx) =
14076                    workspace.active_pane().update(cx, |pane, _| {
14077                        (pane.preview_item_id(), pane.preview_item_idx())
14078                    });
14079
14080                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
14081
14082                if let Some(preview_item_id) = preview_item_id {
14083                    workspace.active_pane().update(cx, |pane, cx| {
14084                        pane.remove_item(preview_item_id, false, false, window, cx);
14085                    });
14086                }
14087            } else {
14088                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
14089            }
14090        }
14091        workspace.active_pane().update(cx, |pane, cx| {
14092            pane.set_preview_item_id(Some(item_id), cx);
14093        });
14094    }
14095
14096    pub fn rename(
14097        &mut self,
14098        _: &Rename,
14099        window: &mut Window,
14100        cx: &mut Context<Self>,
14101    ) -> Option<Task<Result<()>>> {
14102        use language::ToOffset as _;
14103
14104        let provider = self.semantics_provider.clone()?;
14105        let selection = self.selections.newest_anchor().clone();
14106        let (cursor_buffer, cursor_buffer_position) = self
14107            .buffer
14108            .read(cx)
14109            .text_anchor_for_position(selection.head(), cx)?;
14110        let (tail_buffer, cursor_buffer_position_end) = self
14111            .buffer
14112            .read(cx)
14113            .text_anchor_for_position(selection.tail(), cx)?;
14114        if tail_buffer != cursor_buffer {
14115            return None;
14116        }
14117
14118        let snapshot = cursor_buffer.read(cx).snapshot();
14119        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
14120        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
14121        let prepare_rename = provider
14122            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
14123            .unwrap_or_else(|| Task::ready(Ok(None)));
14124        drop(snapshot);
14125
14126        Some(cx.spawn_in(window, async move |this, cx| {
14127            let rename_range = if let Some(range) = prepare_rename.await? {
14128                Some(range)
14129            } else {
14130                this.update(cx, |this, cx| {
14131                    let buffer = this.buffer.read(cx).snapshot(cx);
14132                    let mut buffer_highlights = this
14133                        .document_highlights_for_position(selection.head(), &buffer)
14134                        .filter(|highlight| {
14135                            highlight.start.excerpt_id == selection.head().excerpt_id
14136                                && highlight.end.excerpt_id == selection.head().excerpt_id
14137                        });
14138                    buffer_highlights
14139                        .next()
14140                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
14141                })?
14142            };
14143            if let Some(rename_range) = rename_range {
14144                this.update_in(cx, |this, window, cx| {
14145                    let snapshot = cursor_buffer.read(cx).snapshot();
14146                    let rename_buffer_range = rename_range.to_offset(&snapshot);
14147                    let cursor_offset_in_rename_range =
14148                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
14149                    let cursor_offset_in_rename_range_end =
14150                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
14151
14152                    this.take_rename(false, window, cx);
14153                    let buffer = this.buffer.read(cx).read(cx);
14154                    let cursor_offset = selection.head().to_offset(&buffer);
14155                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
14156                    let rename_end = rename_start + rename_buffer_range.len();
14157                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
14158                    let mut old_highlight_id = None;
14159                    let old_name: Arc<str> = buffer
14160                        .chunks(rename_start..rename_end, true)
14161                        .map(|chunk| {
14162                            if old_highlight_id.is_none() {
14163                                old_highlight_id = chunk.syntax_highlight_id;
14164                            }
14165                            chunk.text
14166                        })
14167                        .collect::<String>()
14168                        .into();
14169
14170                    drop(buffer);
14171
14172                    // Position the selection in the rename editor so that it matches the current selection.
14173                    this.show_local_selections = false;
14174                    let rename_editor = cx.new(|cx| {
14175                        let mut editor = Editor::single_line(window, cx);
14176                        editor.buffer.update(cx, |buffer, cx| {
14177                            buffer.edit([(0..0, old_name.clone())], None, cx)
14178                        });
14179                        let rename_selection_range = match cursor_offset_in_rename_range
14180                            .cmp(&cursor_offset_in_rename_range_end)
14181                        {
14182                            Ordering::Equal => {
14183                                editor.select_all(&SelectAll, window, cx);
14184                                return editor;
14185                            }
14186                            Ordering::Less => {
14187                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
14188                            }
14189                            Ordering::Greater => {
14190                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
14191                            }
14192                        };
14193                        if rename_selection_range.end > old_name.len() {
14194                            editor.select_all(&SelectAll, window, cx);
14195                        } else {
14196                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14197                                s.select_ranges([rename_selection_range]);
14198                            });
14199                        }
14200                        editor
14201                    });
14202                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
14203                        if e == &EditorEvent::Focused {
14204                            cx.emit(EditorEvent::FocusedIn)
14205                        }
14206                    })
14207                    .detach();
14208
14209                    let write_highlights =
14210                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
14211                    let read_highlights =
14212                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
14213                    let ranges = write_highlights
14214                        .iter()
14215                        .flat_map(|(_, ranges)| ranges.iter())
14216                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
14217                        .cloned()
14218                        .collect();
14219
14220                    this.highlight_text::<Rename>(
14221                        ranges,
14222                        HighlightStyle {
14223                            fade_out: Some(0.6),
14224                            ..Default::default()
14225                        },
14226                        cx,
14227                    );
14228                    let rename_focus_handle = rename_editor.focus_handle(cx);
14229                    window.focus(&rename_focus_handle);
14230                    let block_id = this.insert_blocks(
14231                        [BlockProperties {
14232                            style: BlockStyle::Flex,
14233                            placement: BlockPlacement::Below(range.start),
14234                            height: Some(1),
14235                            render: Arc::new({
14236                                let rename_editor = rename_editor.clone();
14237                                move |cx: &mut BlockContext| {
14238                                    let mut text_style = cx.editor_style.text.clone();
14239                                    if let Some(highlight_style) = old_highlight_id
14240                                        .and_then(|h| h.style(&cx.editor_style.syntax))
14241                                    {
14242                                        text_style = text_style.highlight(highlight_style);
14243                                    }
14244                                    div()
14245                                        .block_mouse_down()
14246                                        .pl(cx.anchor_x)
14247                                        .child(EditorElement::new(
14248                                            &rename_editor,
14249                                            EditorStyle {
14250                                                background: cx.theme().system().transparent,
14251                                                local_player: cx.editor_style.local_player,
14252                                                text: text_style,
14253                                                scrollbar_width: cx.editor_style.scrollbar_width,
14254                                                syntax: cx.editor_style.syntax.clone(),
14255                                                status: cx.editor_style.status.clone(),
14256                                                inlay_hints_style: HighlightStyle {
14257                                                    font_weight: Some(FontWeight::BOLD),
14258                                                    ..make_inlay_hints_style(cx.app)
14259                                                },
14260                                                inline_completion_styles: make_suggestion_styles(
14261                                                    cx.app,
14262                                                ),
14263                                                ..EditorStyle::default()
14264                                            },
14265                                        ))
14266                                        .into_any_element()
14267                                }
14268                            }),
14269                            priority: 0,
14270                        }],
14271                        Some(Autoscroll::fit()),
14272                        cx,
14273                    )[0];
14274                    this.pending_rename = Some(RenameState {
14275                        range,
14276                        old_name,
14277                        editor: rename_editor,
14278                        block_id,
14279                    });
14280                })?;
14281            }
14282
14283            Ok(())
14284        }))
14285    }
14286
14287    pub fn confirm_rename(
14288        &mut self,
14289        _: &ConfirmRename,
14290        window: &mut Window,
14291        cx: &mut Context<Self>,
14292    ) -> Option<Task<Result<()>>> {
14293        let rename = self.take_rename(false, window, cx)?;
14294        let workspace = self.workspace()?.downgrade();
14295        let (buffer, start) = self
14296            .buffer
14297            .read(cx)
14298            .text_anchor_for_position(rename.range.start, cx)?;
14299        let (end_buffer, _) = self
14300            .buffer
14301            .read(cx)
14302            .text_anchor_for_position(rename.range.end, cx)?;
14303        if buffer != end_buffer {
14304            return None;
14305        }
14306
14307        let old_name = rename.old_name;
14308        let new_name = rename.editor.read(cx).text(cx);
14309
14310        let rename = self.semantics_provider.as_ref()?.perform_rename(
14311            &buffer,
14312            start,
14313            new_name.clone(),
14314            cx,
14315        )?;
14316
14317        Some(cx.spawn_in(window, async move |editor, cx| {
14318            let project_transaction = rename.await?;
14319            Self::open_project_transaction(
14320                &editor,
14321                workspace,
14322                project_transaction,
14323                format!("Rename: {}{}", old_name, new_name),
14324                cx,
14325            )
14326            .await?;
14327
14328            editor.update(cx, |editor, cx| {
14329                editor.refresh_document_highlights(cx);
14330            })?;
14331            Ok(())
14332        }))
14333    }
14334
14335    fn take_rename(
14336        &mut self,
14337        moving_cursor: bool,
14338        window: &mut Window,
14339        cx: &mut Context<Self>,
14340    ) -> Option<RenameState> {
14341        let rename = self.pending_rename.take()?;
14342        if rename.editor.focus_handle(cx).is_focused(window) {
14343            window.focus(&self.focus_handle);
14344        }
14345
14346        self.remove_blocks(
14347            [rename.block_id].into_iter().collect(),
14348            Some(Autoscroll::fit()),
14349            cx,
14350        );
14351        self.clear_highlights::<Rename>(cx);
14352        self.show_local_selections = true;
14353
14354        if moving_cursor {
14355            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
14356                editor.selections.newest::<usize>(cx).head()
14357            });
14358
14359            // Update the selection to match the position of the selection inside
14360            // the rename editor.
14361            let snapshot = self.buffer.read(cx).read(cx);
14362            let rename_range = rename.range.to_offset(&snapshot);
14363            let cursor_in_editor = snapshot
14364                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
14365                .min(rename_range.end);
14366            drop(snapshot);
14367
14368            self.change_selections(None, window, cx, |s| {
14369                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
14370            });
14371        } else {
14372            self.refresh_document_highlights(cx);
14373        }
14374
14375        Some(rename)
14376    }
14377
14378    pub fn pending_rename(&self) -> Option<&RenameState> {
14379        self.pending_rename.as_ref()
14380    }
14381
14382    fn format(
14383        &mut self,
14384        _: &Format,
14385        window: &mut Window,
14386        cx: &mut Context<Self>,
14387    ) -> Option<Task<Result<()>>> {
14388        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
14389
14390        let project = match &self.project {
14391            Some(project) => project.clone(),
14392            None => return None,
14393        };
14394
14395        Some(self.perform_format(
14396            project,
14397            FormatTrigger::Manual,
14398            FormatTarget::Buffers,
14399            window,
14400            cx,
14401        ))
14402    }
14403
14404    fn format_selections(
14405        &mut self,
14406        _: &FormatSelections,
14407        window: &mut Window,
14408        cx: &mut Context<Self>,
14409    ) -> Option<Task<Result<()>>> {
14410        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
14411
14412        let project = match &self.project {
14413            Some(project) => project.clone(),
14414            None => return None,
14415        };
14416
14417        let ranges = self
14418            .selections
14419            .all_adjusted(cx)
14420            .into_iter()
14421            .map(|selection| selection.range())
14422            .collect_vec();
14423
14424        Some(self.perform_format(
14425            project,
14426            FormatTrigger::Manual,
14427            FormatTarget::Ranges(ranges),
14428            window,
14429            cx,
14430        ))
14431    }
14432
14433    fn perform_format(
14434        &mut self,
14435        project: Entity<Project>,
14436        trigger: FormatTrigger,
14437        target: FormatTarget,
14438        window: &mut Window,
14439        cx: &mut Context<Self>,
14440    ) -> Task<Result<()>> {
14441        let buffer = self.buffer.clone();
14442        let (buffers, target) = match target {
14443            FormatTarget::Buffers => {
14444                let mut buffers = buffer.read(cx).all_buffers();
14445                if trigger == FormatTrigger::Save {
14446                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
14447                }
14448                (buffers, LspFormatTarget::Buffers)
14449            }
14450            FormatTarget::Ranges(selection_ranges) => {
14451                let multi_buffer = buffer.read(cx);
14452                let snapshot = multi_buffer.read(cx);
14453                let mut buffers = HashSet::default();
14454                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
14455                    BTreeMap::new();
14456                for selection_range in selection_ranges {
14457                    for (buffer, buffer_range, _) in
14458                        snapshot.range_to_buffer_ranges(selection_range)
14459                    {
14460                        let buffer_id = buffer.remote_id();
14461                        let start = buffer.anchor_before(buffer_range.start);
14462                        let end = buffer.anchor_after(buffer_range.end);
14463                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
14464                        buffer_id_to_ranges
14465                            .entry(buffer_id)
14466                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
14467                            .or_insert_with(|| vec![start..end]);
14468                    }
14469                }
14470                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
14471            }
14472        };
14473
14474        let transaction_id_prev = buffer.read_with(cx, |b, cx| b.last_transaction_id(cx));
14475        let selections_prev = transaction_id_prev
14476            .and_then(|transaction_id_prev| {
14477                // default to selections as they were after the last edit, if we have them,
14478                // instead of how they are now.
14479                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
14480                // will take you back to where you made the last edit, instead of staying where you scrolled
14481                self.selection_history
14482                    .transaction(transaction_id_prev)
14483                    .map(|t| t.0.clone())
14484            })
14485            .unwrap_or_else(|| {
14486                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
14487                self.selections.disjoint_anchors()
14488            });
14489
14490        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
14491        let format = project.update(cx, |project, cx| {
14492            project.format(buffers, target, true, trigger, cx)
14493        });
14494
14495        cx.spawn_in(window, async move |editor, cx| {
14496            let transaction = futures::select_biased! {
14497                transaction = format.log_err().fuse() => transaction,
14498                () = timeout => {
14499                    log::warn!("timed out waiting for formatting");
14500                    None
14501                }
14502            };
14503
14504            buffer
14505                .update(cx, |buffer, cx| {
14506                    if let Some(transaction) = transaction {
14507                        if !buffer.is_singleton() {
14508                            buffer.push_transaction(&transaction.0, cx);
14509                        }
14510                    }
14511                    cx.notify();
14512                })
14513                .ok();
14514
14515            if let Some(transaction_id_now) =
14516                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
14517            {
14518                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
14519                if has_new_transaction {
14520                    _ = editor.update(cx, |editor, _| {
14521                        editor
14522                            .selection_history
14523                            .insert_transaction(transaction_id_now, selections_prev);
14524                    });
14525                }
14526            }
14527
14528            Ok(())
14529        })
14530    }
14531
14532    fn organize_imports(
14533        &mut self,
14534        _: &OrganizeImports,
14535        window: &mut Window,
14536        cx: &mut Context<Self>,
14537    ) -> Option<Task<Result<()>>> {
14538        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
14539        let project = match &self.project {
14540            Some(project) => project.clone(),
14541            None => return None,
14542        };
14543        Some(self.perform_code_action_kind(
14544            project,
14545            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
14546            window,
14547            cx,
14548        ))
14549    }
14550
14551    fn perform_code_action_kind(
14552        &mut self,
14553        project: Entity<Project>,
14554        kind: CodeActionKind,
14555        window: &mut Window,
14556        cx: &mut Context<Self>,
14557    ) -> Task<Result<()>> {
14558        let buffer = self.buffer.clone();
14559        let buffers = buffer.read(cx).all_buffers();
14560        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
14561        let apply_action = project.update(cx, |project, cx| {
14562            project.apply_code_action_kind(buffers, kind, true, cx)
14563        });
14564        cx.spawn_in(window, async move |_, cx| {
14565            let transaction = futures::select_biased! {
14566                () = timeout => {
14567                    log::warn!("timed out waiting for executing code action");
14568                    None
14569                }
14570                transaction = apply_action.log_err().fuse() => transaction,
14571            };
14572            buffer
14573                .update(cx, |buffer, cx| {
14574                    // check if we need this
14575                    if let Some(transaction) = transaction {
14576                        if !buffer.is_singleton() {
14577                            buffer.push_transaction(&transaction.0, cx);
14578                        }
14579                    }
14580                    cx.notify();
14581                })
14582                .ok();
14583            Ok(())
14584        })
14585    }
14586
14587    fn restart_language_server(
14588        &mut self,
14589        _: &RestartLanguageServer,
14590        _: &mut Window,
14591        cx: &mut Context<Self>,
14592    ) {
14593        if let Some(project) = self.project.clone() {
14594            self.buffer.update(cx, |multi_buffer, cx| {
14595                project.update(cx, |project, cx| {
14596                    project.restart_language_servers_for_buffers(
14597                        multi_buffer.all_buffers().into_iter().collect(),
14598                        cx,
14599                    );
14600                });
14601            })
14602        }
14603    }
14604
14605    fn stop_language_server(
14606        &mut self,
14607        _: &StopLanguageServer,
14608        _: &mut Window,
14609        cx: &mut Context<Self>,
14610    ) {
14611        if let Some(project) = self.project.clone() {
14612            self.buffer.update(cx, |multi_buffer, cx| {
14613                project.update(cx, |project, cx| {
14614                    project.stop_language_servers_for_buffers(
14615                        multi_buffer.all_buffers().into_iter().collect(),
14616                        cx,
14617                    );
14618                    cx.emit(project::Event::RefreshInlayHints);
14619                });
14620            });
14621        }
14622    }
14623
14624    fn cancel_language_server_work(
14625        workspace: &mut Workspace,
14626        _: &actions::CancelLanguageServerWork,
14627        _: &mut Window,
14628        cx: &mut Context<Workspace>,
14629    ) {
14630        let project = workspace.project();
14631        let buffers = workspace
14632            .active_item(cx)
14633            .and_then(|item| item.act_as::<Editor>(cx))
14634            .map_or(HashSet::default(), |editor| {
14635                editor.read(cx).buffer.read(cx).all_buffers()
14636            });
14637        project.update(cx, |project, cx| {
14638            project.cancel_language_server_work_for_buffers(buffers, cx);
14639        });
14640    }
14641
14642    fn show_character_palette(
14643        &mut self,
14644        _: &ShowCharacterPalette,
14645        window: &mut Window,
14646        _: &mut Context<Self>,
14647    ) {
14648        window.show_character_palette();
14649    }
14650
14651    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
14652        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
14653            let buffer = self.buffer.read(cx).snapshot(cx);
14654            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
14655            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
14656            let is_valid = buffer
14657                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
14658                .any(|entry| {
14659                    entry.diagnostic.is_primary
14660                        && !entry.range.is_empty()
14661                        && entry.range.start == primary_range_start
14662                        && entry.diagnostic.message == active_diagnostics.active_message
14663                });
14664
14665            if !is_valid {
14666                self.dismiss_diagnostics(cx);
14667            }
14668        }
14669    }
14670
14671    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
14672        match &self.active_diagnostics {
14673            ActiveDiagnostic::Group(group) => Some(group),
14674            _ => None,
14675        }
14676    }
14677
14678    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
14679        self.dismiss_diagnostics(cx);
14680        self.active_diagnostics = ActiveDiagnostic::All;
14681    }
14682
14683    fn activate_diagnostics(
14684        &mut self,
14685        buffer_id: BufferId,
14686        diagnostic: DiagnosticEntry<usize>,
14687        window: &mut Window,
14688        cx: &mut Context<Self>,
14689    ) {
14690        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
14691            return;
14692        }
14693        self.dismiss_diagnostics(cx);
14694        let snapshot = self.snapshot(window, cx);
14695        let Some(diagnostic_renderer) = cx
14696            .try_global::<GlobalDiagnosticRenderer>()
14697            .map(|g| g.0.clone())
14698        else {
14699            return;
14700        };
14701        let buffer = self.buffer.read(cx).snapshot(cx);
14702
14703        let diagnostic_group = buffer
14704            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
14705            .collect::<Vec<_>>();
14706
14707        let blocks = diagnostic_renderer.render_group(
14708            diagnostic_group,
14709            buffer_id,
14710            snapshot,
14711            cx.weak_entity(),
14712            cx,
14713        );
14714
14715        let blocks = self.display_map.update(cx, |display_map, cx| {
14716            display_map.insert_blocks(blocks, cx).into_iter().collect()
14717        });
14718        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
14719            active_range: buffer.anchor_before(diagnostic.range.start)
14720                ..buffer.anchor_after(diagnostic.range.end),
14721            active_message: diagnostic.diagnostic.message.clone(),
14722            group_id: diagnostic.diagnostic.group_id,
14723            blocks,
14724        });
14725        cx.notify();
14726    }
14727
14728    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
14729        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
14730            return;
14731        };
14732
14733        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
14734        if let ActiveDiagnostic::Group(group) = prev {
14735            self.display_map.update(cx, |display_map, cx| {
14736                display_map.remove_blocks(group.blocks, cx);
14737            });
14738            cx.notify();
14739        }
14740    }
14741
14742    /// Disable inline diagnostics rendering for this editor.
14743    pub fn disable_inline_diagnostics(&mut self) {
14744        self.inline_diagnostics_enabled = false;
14745        self.inline_diagnostics_update = Task::ready(());
14746        self.inline_diagnostics.clear();
14747    }
14748
14749    pub fn inline_diagnostics_enabled(&self) -> bool {
14750        self.inline_diagnostics_enabled
14751    }
14752
14753    pub fn show_inline_diagnostics(&self) -> bool {
14754        self.show_inline_diagnostics
14755    }
14756
14757    pub fn toggle_inline_diagnostics(
14758        &mut self,
14759        _: &ToggleInlineDiagnostics,
14760        window: &mut Window,
14761        cx: &mut Context<Editor>,
14762    ) {
14763        self.show_inline_diagnostics = !self.show_inline_diagnostics;
14764        self.refresh_inline_diagnostics(false, window, cx);
14765    }
14766
14767    fn refresh_inline_diagnostics(
14768        &mut self,
14769        debounce: bool,
14770        window: &mut Window,
14771        cx: &mut Context<Self>,
14772    ) {
14773        if !self.inline_diagnostics_enabled || !self.show_inline_diagnostics {
14774            self.inline_diagnostics_update = Task::ready(());
14775            self.inline_diagnostics.clear();
14776            return;
14777        }
14778
14779        let debounce_ms = ProjectSettings::get_global(cx)
14780            .diagnostics
14781            .inline
14782            .update_debounce_ms;
14783        let debounce = if debounce && debounce_ms > 0 {
14784            Some(Duration::from_millis(debounce_ms))
14785        } else {
14786            None
14787        };
14788        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
14789            let editor = editor.upgrade().unwrap();
14790
14791            if let Some(debounce) = debounce {
14792                cx.background_executor().timer(debounce).await;
14793            }
14794            let Some(snapshot) = editor
14795                .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
14796                .ok()
14797            else {
14798                return;
14799            };
14800
14801            let new_inline_diagnostics = cx
14802                .background_spawn(async move {
14803                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
14804                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
14805                        let message = diagnostic_entry
14806                            .diagnostic
14807                            .message
14808                            .split_once('\n')
14809                            .map(|(line, _)| line)
14810                            .map(SharedString::new)
14811                            .unwrap_or_else(|| {
14812                                SharedString::from(diagnostic_entry.diagnostic.message)
14813                            });
14814                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
14815                        let (Ok(i) | Err(i)) = inline_diagnostics
14816                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
14817                        inline_diagnostics.insert(
14818                            i,
14819                            (
14820                                start_anchor,
14821                                InlineDiagnostic {
14822                                    message,
14823                                    group_id: diagnostic_entry.diagnostic.group_id,
14824                                    start: diagnostic_entry.range.start.to_point(&snapshot),
14825                                    is_primary: diagnostic_entry.diagnostic.is_primary,
14826                                    severity: diagnostic_entry.diagnostic.severity,
14827                                },
14828                            ),
14829                        );
14830                    }
14831                    inline_diagnostics
14832                })
14833                .await;
14834
14835            editor
14836                .update(cx, |editor, cx| {
14837                    editor.inline_diagnostics = new_inline_diagnostics;
14838                    cx.notify();
14839                })
14840                .ok();
14841        });
14842    }
14843
14844    pub fn set_selections_from_remote(
14845        &mut self,
14846        selections: Vec<Selection<Anchor>>,
14847        pending_selection: Option<Selection<Anchor>>,
14848        window: &mut Window,
14849        cx: &mut Context<Self>,
14850    ) {
14851        let old_cursor_position = self.selections.newest_anchor().head();
14852        self.selections.change_with(cx, |s| {
14853            s.select_anchors(selections);
14854            if let Some(pending_selection) = pending_selection {
14855                s.set_pending(pending_selection, SelectMode::Character);
14856            } else {
14857                s.clear_pending();
14858            }
14859        });
14860        self.selections_did_change(false, &old_cursor_position, true, window, cx);
14861    }
14862
14863    fn push_to_selection_history(&mut self) {
14864        self.selection_history.push(SelectionHistoryEntry {
14865            selections: self.selections.disjoint_anchors(),
14866            select_next_state: self.select_next_state.clone(),
14867            select_prev_state: self.select_prev_state.clone(),
14868            add_selections_state: self.add_selections_state.clone(),
14869        });
14870    }
14871
14872    pub fn transact(
14873        &mut self,
14874        window: &mut Window,
14875        cx: &mut Context<Self>,
14876        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
14877    ) -> Option<TransactionId> {
14878        self.start_transaction_at(Instant::now(), window, cx);
14879        update(self, window, cx);
14880        self.end_transaction_at(Instant::now(), cx)
14881    }
14882
14883    pub fn start_transaction_at(
14884        &mut self,
14885        now: Instant,
14886        window: &mut Window,
14887        cx: &mut Context<Self>,
14888    ) {
14889        self.end_selection(window, cx);
14890        if let Some(tx_id) = self
14891            .buffer
14892            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
14893        {
14894            self.selection_history
14895                .insert_transaction(tx_id, self.selections.disjoint_anchors());
14896            cx.emit(EditorEvent::TransactionBegun {
14897                transaction_id: tx_id,
14898            })
14899        }
14900    }
14901
14902    pub fn end_transaction_at(
14903        &mut self,
14904        now: Instant,
14905        cx: &mut Context<Self>,
14906    ) -> Option<TransactionId> {
14907        if let Some(transaction_id) = self
14908            .buffer
14909            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
14910        {
14911            if let Some((_, end_selections)) =
14912                self.selection_history.transaction_mut(transaction_id)
14913            {
14914                *end_selections = Some(self.selections.disjoint_anchors());
14915            } else {
14916                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
14917            }
14918
14919            cx.emit(EditorEvent::Edited { transaction_id });
14920            Some(transaction_id)
14921        } else {
14922            None
14923        }
14924    }
14925
14926    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
14927        if self.selection_mark_mode {
14928            self.change_selections(None, window, cx, |s| {
14929                s.move_with(|_, sel| {
14930                    sel.collapse_to(sel.head(), SelectionGoal::None);
14931                });
14932            })
14933        }
14934        self.selection_mark_mode = true;
14935        cx.notify();
14936    }
14937
14938    pub fn swap_selection_ends(
14939        &mut self,
14940        _: &actions::SwapSelectionEnds,
14941        window: &mut Window,
14942        cx: &mut Context<Self>,
14943    ) {
14944        self.change_selections(None, window, cx, |s| {
14945            s.move_with(|_, sel| {
14946                if sel.start != sel.end {
14947                    sel.reversed = !sel.reversed
14948                }
14949            });
14950        });
14951        self.request_autoscroll(Autoscroll::newest(), cx);
14952        cx.notify();
14953    }
14954
14955    pub fn toggle_fold(
14956        &mut self,
14957        _: &actions::ToggleFold,
14958        window: &mut Window,
14959        cx: &mut Context<Self>,
14960    ) {
14961        if self.is_singleton(cx) {
14962            let selection = self.selections.newest::<Point>(cx);
14963
14964            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14965            let range = if selection.is_empty() {
14966                let point = selection.head().to_display_point(&display_map);
14967                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
14968                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
14969                    .to_point(&display_map);
14970                start..end
14971            } else {
14972                selection.range()
14973            };
14974            if display_map.folds_in_range(range).next().is_some() {
14975                self.unfold_lines(&Default::default(), window, cx)
14976            } else {
14977                self.fold(&Default::default(), window, cx)
14978            }
14979        } else {
14980            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
14981            let buffer_ids: HashSet<_> = self
14982                .selections
14983                .disjoint_anchor_ranges()
14984                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
14985                .collect();
14986
14987            let should_unfold = buffer_ids
14988                .iter()
14989                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
14990
14991            for buffer_id in buffer_ids {
14992                if should_unfold {
14993                    self.unfold_buffer(buffer_id, cx);
14994                } else {
14995                    self.fold_buffer(buffer_id, cx);
14996                }
14997            }
14998        }
14999    }
15000
15001    pub fn toggle_fold_recursive(
15002        &mut self,
15003        _: &actions::ToggleFoldRecursive,
15004        window: &mut Window,
15005        cx: &mut Context<Self>,
15006    ) {
15007        let selection = self.selections.newest::<Point>(cx);
15008
15009        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15010        let range = if selection.is_empty() {
15011            let point = selection.head().to_display_point(&display_map);
15012            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15013            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15014                .to_point(&display_map);
15015            start..end
15016        } else {
15017            selection.range()
15018        };
15019        if display_map.folds_in_range(range).next().is_some() {
15020            self.unfold_recursive(&Default::default(), window, cx)
15021        } else {
15022            self.fold_recursive(&Default::default(), window, cx)
15023        }
15024    }
15025
15026    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
15027        if self.is_singleton(cx) {
15028            let mut to_fold = Vec::new();
15029            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15030            let selections = self.selections.all_adjusted(cx);
15031
15032            for selection in selections {
15033                let range = selection.range().sorted();
15034                let buffer_start_row = range.start.row;
15035
15036                if range.start.row != range.end.row {
15037                    let mut found = false;
15038                    let mut row = range.start.row;
15039                    while row <= range.end.row {
15040                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
15041                        {
15042                            found = true;
15043                            row = crease.range().end.row + 1;
15044                            to_fold.push(crease);
15045                        } else {
15046                            row += 1
15047                        }
15048                    }
15049                    if found {
15050                        continue;
15051                    }
15052                }
15053
15054                for row in (0..=range.start.row).rev() {
15055                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15056                        if crease.range().end.row >= buffer_start_row {
15057                            to_fold.push(crease);
15058                            if row <= range.start.row {
15059                                break;
15060                            }
15061                        }
15062                    }
15063                }
15064            }
15065
15066            self.fold_creases(to_fold, true, window, cx);
15067        } else {
15068            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15069            let buffer_ids = self
15070                .selections
15071                .disjoint_anchor_ranges()
15072                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15073                .collect::<HashSet<_>>();
15074            for buffer_id in buffer_ids {
15075                self.fold_buffer(buffer_id, cx);
15076            }
15077        }
15078    }
15079
15080    fn fold_at_level(
15081        &mut self,
15082        fold_at: &FoldAtLevel,
15083        window: &mut Window,
15084        cx: &mut Context<Self>,
15085    ) {
15086        if !self.buffer.read(cx).is_singleton() {
15087            return;
15088        }
15089
15090        let fold_at_level = fold_at.0;
15091        let snapshot = self.buffer.read(cx).snapshot(cx);
15092        let mut to_fold = Vec::new();
15093        let mut stack = vec![(0, snapshot.max_row().0, 1)];
15094
15095        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
15096            while start_row < end_row {
15097                match self
15098                    .snapshot(window, cx)
15099                    .crease_for_buffer_row(MultiBufferRow(start_row))
15100                {
15101                    Some(crease) => {
15102                        let nested_start_row = crease.range().start.row + 1;
15103                        let nested_end_row = crease.range().end.row;
15104
15105                        if current_level < fold_at_level {
15106                            stack.push((nested_start_row, nested_end_row, current_level + 1));
15107                        } else if current_level == fold_at_level {
15108                            to_fold.push(crease);
15109                        }
15110
15111                        start_row = nested_end_row + 1;
15112                    }
15113                    None => start_row += 1,
15114                }
15115            }
15116        }
15117
15118        self.fold_creases(to_fold, true, window, cx);
15119    }
15120
15121    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
15122        if self.buffer.read(cx).is_singleton() {
15123            let mut fold_ranges = Vec::new();
15124            let snapshot = self.buffer.read(cx).snapshot(cx);
15125
15126            for row in 0..snapshot.max_row().0 {
15127                if let Some(foldable_range) = self
15128                    .snapshot(window, cx)
15129                    .crease_for_buffer_row(MultiBufferRow(row))
15130                {
15131                    fold_ranges.push(foldable_range);
15132                }
15133            }
15134
15135            self.fold_creases(fold_ranges, true, window, cx);
15136        } else {
15137            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
15138                editor
15139                    .update_in(cx, |editor, _, cx| {
15140                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15141                            editor.fold_buffer(buffer_id, cx);
15142                        }
15143                    })
15144                    .ok();
15145            });
15146        }
15147    }
15148
15149    pub fn fold_function_bodies(
15150        &mut self,
15151        _: &actions::FoldFunctionBodies,
15152        window: &mut Window,
15153        cx: &mut Context<Self>,
15154    ) {
15155        let snapshot = self.buffer.read(cx).snapshot(cx);
15156
15157        let ranges = snapshot
15158            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
15159            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
15160            .collect::<Vec<_>>();
15161
15162        let creases = ranges
15163            .into_iter()
15164            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
15165            .collect();
15166
15167        self.fold_creases(creases, true, window, cx);
15168    }
15169
15170    pub fn fold_recursive(
15171        &mut self,
15172        _: &actions::FoldRecursive,
15173        window: &mut Window,
15174        cx: &mut Context<Self>,
15175    ) {
15176        let mut to_fold = Vec::new();
15177        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15178        let selections = self.selections.all_adjusted(cx);
15179
15180        for selection in selections {
15181            let range = selection.range().sorted();
15182            let buffer_start_row = range.start.row;
15183
15184            if range.start.row != range.end.row {
15185                let mut found = false;
15186                for row in range.start.row..=range.end.row {
15187                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15188                        found = true;
15189                        to_fold.push(crease);
15190                    }
15191                }
15192                if found {
15193                    continue;
15194                }
15195            }
15196
15197            for row in (0..=range.start.row).rev() {
15198                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15199                    if crease.range().end.row >= buffer_start_row {
15200                        to_fold.push(crease);
15201                    } else {
15202                        break;
15203                    }
15204                }
15205            }
15206        }
15207
15208        self.fold_creases(to_fold, true, window, cx);
15209    }
15210
15211    pub fn fold_at(
15212        &mut self,
15213        buffer_row: MultiBufferRow,
15214        window: &mut Window,
15215        cx: &mut Context<Self>,
15216    ) {
15217        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15218
15219        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
15220            let autoscroll = self
15221                .selections
15222                .all::<Point>(cx)
15223                .iter()
15224                .any(|selection| crease.range().overlaps(&selection.range()));
15225
15226            self.fold_creases(vec![crease], autoscroll, window, cx);
15227        }
15228    }
15229
15230    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
15231        if self.is_singleton(cx) {
15232            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15233            let buffer = &display_map.buffer_snapshot;
15234            let selections = self.selections.all::<Point>(cx);
15235            let ranges = selections
15236                .iter()
15237                .map(|s| {
15238                    let range = s.display_range(&display_map).sorted();
15239                    let mut start = range.start.to_point(&display_map);
15240                    let mut end = range.end.to_point(&display_map);
15241                    start.column = 0;
15242                    end.column = buffer.line_len(MultiBufferRow(end.row));
15243                    start..end
15244                })
15245                .collect::<Vec<_>>();
15246
15247            self.unfold_ranges(&ranges, true, true, cx);
15248        } else {
15249            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15250            let buffer_ids = self
15251                .selections
15252                .disjoint_anchor_ranges()
15253                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15254                .collect::<HashSet<_>>();
15255            for buffer_id in buffer_ids {
15256                self.unfold_buffer(buffer_id, cx);
15257            }
15258        }
15259    }
15260
15261    pub fn unfold_recursive(
15262        &mut self,
15263        _: &UnfoldRecursive,
15264        _window: &mut Window,
15265        cx: &mut Context<Self>,
15266    ) {
15267        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15268        let selections = self.selections.all::<Point>(cx);
15269        let ranges = selections
15270            .iter()
15271            .map(|s| {
15272                let mut range = s.display_range(&display_map).sorted();
15273                *range.start.column_mut() = 0;
15274                *range.end.column_mut() = display_map.line_len(range.end.row());
15275                let start = range.start.to_point(&display_map);
15276                let end = range.end.to_point(&display_map);
15277                start..end
15278            })
15279            .collect::<Vec<_>>();
15280
15281        self.unfold_ranges(&ranges, true, true, cx);
15282    }
15283
15284    pub fn unfold_at(
15285        &mut self,
15286        buffer_row: MultiBufferRow,
15287        _window: &mut Window,
15288        cx: &mut Context<Self>,
15289    ) {
15290        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15291
15292        let intersection_range = Point::new(buffer_row.0, 0)
15293            ..Point::new(
15294                buffer_row.0,
15295                display_map.buffer_snapshot.line_len(buffer_row),
15296            );
15297
15298        let autoscroll = self
15299            .selections
15300            .all::<Point>(cx)
15301            .iter()
15302            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
15303
15304        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
15305    }
15306
15307    pub fn unfold_all(
15308        &mut self,
15309        _: &actions::UnfoldAll,
15310        _window: &mut Window,
15311        cx: &mut Context<Self>,
15312    ) {
15313        if self.buffer.read(cx).is_singleton() {
15314            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15315            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
15316        } else {
15317            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
15318                editor
15319                    .update(cx, |editor, cx| {
15320                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15321                            editor.unfold_buffer(buffer_id, cx);
15322                        }
15323                    })
15324                    .ok();
15325            });
15326        }
15327    }
15328
15329    pub fn fold_selected_ranges(
15330        &mut self,
15331        _: &FoldSelectedRanges,
15332        window: &mut Window,
15333        cx: &mut Context<Self>,
15334    ) {
15335        let selections = self.selections.all_adjusted(cx);
15336        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15337        let ranges = selections
15338            .into_iter()
15339            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
15340            .collect::<Vec<_>>();
15341        self.fold_creases(ranges, true, window, cx);
15342    }
15343
15344    pub fn fold_ranges<T: ToOffset + Clone>(
15345        &mut self,
15346        ranges: Vec<Range<T>>,
15347        auto_scroll: bool,
15348        window: &mut Window,
15349        cx: &mut Context<Self>,
15350    ) {
15351        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15352        let ranges = ranges
15353            .into_iter()
15354            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
15355            .collect::<Vec<_>>();
15356        self.fold_creases(ranges, auto_scroll, window, cx);
15357    }
15358
15359    pub fn fold_creases<T: ToOffset + Clone>(
15360        &mut self,
15361        creases: Vec<Crease<T>>,
15362        auto_scroll: bool,
15363        _window: &mut Window,
15364        cx: &mut Context<Self>,
15365    ) {
15366        if creases.is_empty() {
15367            return;
15368        }
15369
15370        let mut buffers_affected = HashSet::default();
15371        let multi_buffer = self.buffer().read(cx);
15372        for crease in &creases {
15373            if let Some((_, buffer, _)) =
15374                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
15375            {
15376                buffers_affected.insert(buffer.read(cx).remote_id());
15377            };
15378        }
15379
15380        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
15381
15382        if auto_scroll {
15383            self.request_autoscroll(Autoscroll::fit(), cx);
15384        }
15385
15386        cx.notify();
15387
15388        self.scrollbar_marker_state.dirty = true;
15389        self.folds_did_change(cx);
15390    }
15391
15392    /// Removes any folds whose ranges intersect any of the given ranges.
15393    pub fn unfold_ranges<T: ToOffset + Clone>(
15394        &mut self,
15395        ranges: &[Range<T>],
15396        inclusive: bool,
15397        auto_scroll: bool,
15398        cx: &mut Context<Self>,
15399    ) {
15400        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
15401            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
15402        });
15403        self.folds_did_change(cx);
15404    }
15405
15406    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
15407        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
15408            return;
15409        }
15410        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
15411        self.display_map.update(cx, |display_map, cx| {
15412            display_map.fold_buffers([buffer_id], cx)
15413        });
15414        cx.emit(EditorEvent::BufferFoldToggled {
15415            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
15416            folded: true,
15417        });
15418        cx.notify();
15419    }
15420
15421    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
15422        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
15423            return;
15424        }
15425        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
15426        self.display_map.update(cx, |display_map, cx| {
15427            display_map.unfold_buffers([buffer_id], cx);
15428        });
15429        cx.emit(EditorEvent::BufferFoldToggled {
15430            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
15431            folded: false,
15432        });
15433        cx.notify();
15434    }
15435
15436    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
15437        self.display_map.read(cx).is_buffer_folded(buffer)
15438    }
15439
15440    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
15441        self.display_map.read(cx).folded_buffers()
15442    }
15443
15444    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
15445        self.display_map.update(cx, |display_map, cx| {
15446            display_map.disable_header_for_buffer(buffer_id, cx);
15447        });
15448        cx.notify();
15449    }
15450
15451    /// Removes any folds with the given ranges.
15452    pub fn remove_folds_with_type<T: ToOffset + Clone>(
15453        &mut self,
15454        ranges: &[Range<T>],
15455        type_id: TypeId,
15456        auto_scroll: bool,
15457        cx: &mut Context<Self>,
15458    ) {
15459        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
15460            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
15461        });
15462        self.folds_did_change(cx);
15463    }
15464
15465    fn remove_folds_with<T: ToOffset + Clone>(
15466        &mut self,
15467        ranges: &[Range<T>],
15468        auto_scroll: bool,
15469        cx: &mut Context<Self>,
15470        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
15471    ) {
15472        if ranges.is_empty() {
15473            return;
15474        }
15475
15476        let mut buffers_affected = HashSet::default();
15477        let multi_buffer = self.buffer().read(cx);
15478        for range in ranges {
15479            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
15480                buffers_affected.insert(buffer.read(cx).remote_id());
15481            };
15482        }
15483
15484        self.display_map.update(cx, update);
15485
15486        if auto_scroll {
15487            self.request_autoscroll(Autoscroll::fit(), cx);
15488        }
15489
15490        cx.notify();
15491        self.scrollbar_marker_state.dirty = true;
15492        self.active_indent_guides_state.dirty = true;
15493    }
15494
15495    pub fn update_fold_widths(
15496        &mut self,
15497        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
15498        cx: &mut Context<Self>,
15499    ) -> bool {
15500        self.display_map
15501            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
15502    }
15503
15504    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
15505        self.display_map.read(cx).fold_placeholder.clone()
15506    }
15507
15508    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
15509        self.buffer.update(cx, |buffer, cx| {
15510            buffer.set_all_diff_hunks_expanded(cx);
15511        });
15512    }
15513
15514    pub fn expand_all_diff_hunks(
15515        &mut self,
15516        _: &ExpandAllDiffHunks,
15517        _window: &mut Window,
15518        cx: &mut Context<Self>,
15519    ) {
15520        self.buffer.update(cx, |buffer, cx| {
15521            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
15522        });
15523    }
15524
15525    pub fn toggle_selected_diff_hunks(
15526        &mut self,
15527        _: &ToggleSelectedDiffHunks,
15528        _window: &mut Window,
15529        cx: &mut Context<Self>,
15530    ) {
15531        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
15532        self.toggle_diff_hunks_in_ranges(ranges, cx);
15533    }
15534
15535    pub fn diff_hunks_in_ranges<'a>(
15536        &'a self,
15537        ranges: &'a [Range<Anchor>],
15538        buffer: &'a MultiBufferSnapshot,
15539    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
15540        ranges.iter().flat_map(move |range| {
15541            let end_excerpt_id = range.end.excerpt_id;
15542            let range = range.to_point(buffer);
15543            let mut peek_end = range.end;
15544            if range.end.row < buffer.max_row().0 {
15545                peek_end = Point::new(range.end.row + 1, 0);
15546            }
15547            buffer
15548                .diff_hunks_in_range(range.start..peek_end)
15549                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
15550        })
15551    }
15552
15553    pub fn has_stageable_diff_hunks_in_ranges(
15554        &self,
15555        ranges: &[Range<Anchor>],
15556        snapshot: &MultiBufferSnapshot,
15557    ) -> bool {
15558        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
15559        hunks.any(|hunk| hunk.status().has_secondary_hunk())
15560    }
15561
15562    pub fn toggle_staged_selected_diff_hunks(
15563        &mut self,
15564        _: &::git::ToggleStaged,
15565        _: &mut Window,
15566        cx: &mut Context<Self>,
15567    ) {
15568        let snapshot = self.buffer.read(cx).snapshot(cx);
15569        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
15570        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
15571        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
15572    }
15573
15574    pub fn set_render_diff_hunk_controls(
15575        &mut self,
15576        render_diff_hunk_controls: RenderDiffHunkControlsFn,
15577        cx: &mut Context<Self>,
15578    ) {
15579        self.render_diff_hunk_controls = render_diff_hunk_controls;
15580        cx.notify();
15581    }
15582
15583    pub fn stage_and_next(
15584        &mut self,
15585        _: &::git::StageAndNext,
15586        window: &mut Window,
15587        cx: &mut Context<Self>,
15588    ) {
15589        self.do_stage_or_unstage_and_next(true, window, cx);
15590    }
15591
15592    pub fn unstage_and_next(
15593        &mut self,
15594        _: &::git::UnstageAndNext,
15595        window: &mut Window,
15596        cx: &mut Context<Self>,
15597    ) {
15598        self.do_stage_or_unstage_and_next(false, window, cx);
15599    }
15600
15601    pub fn stage_or_unstage_diff_hunks(
15602        &mut self,
15603        stage: bool,
15604        ranges: Vec<Range<Anchor>>,
15605        cx: &mut Context<Self>,
15606    ) {
15607        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
15608        cx.spawn(async move |this, cx| {
15609            task.await?;
15610            this.update(cx, |this, cx| {
15611                let snapshot = this.buffer.read(cx).snapshot(cx);
15612                let chunk_by = this
15613                    .diff_hunks_in_ranges(&ranges, &snapshot)
15614                    .chunk_by(|hunk| hunk.buffer_id);
15615                for (buffer_id, hunks) in &chunk_by {
15616                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
15617                }
15618            })
15619        })
15620        .detach_and_log_err(cx);
15621    }
15622
15623    fn save_buffers_for_ranges_if_needed(
15624        &mut self,
15625        ranges: &[Range<Anchor>],
15626        cx: &mut Context<Editor>,
15627    ) -> Task<Result<()>> {
15628        let multibuffer = self.buffer.read(cx);
15629        let snapshot = multibuffer.read(cx);
15630        let buffer_ids: HashSet<_> = ranges
15631            .iter()
15632            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
15633            .collect();
15634        drop(snapshot);
15635
15636        let mut buffers = HashSet::default();
15637        for buffer_id in buffer_ids {
15638            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
15639                let buffer = buffer_entity.read(cx);
15640                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
15641                {
15642                    buffers.insert(buffer_entity);
15643                }
15644            }
15645        }
15646
15647        if let Some(project) = &self.project {
15648            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
15649        } else {
15650            Task::ready(Ok(()))
15651        }
15652    }
15653
15654    fn do_stage_or_unstage_and_next(
15655        &mut self,
15656        stage: bool,
15657        window: &mut Window,
15658        cx: &mut Context<Self>,
15659    ) {
15660        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
15661
15662        if ranges.iter().any(|range| range.start != range.end) {
15663            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
15664            return;
15665        }
15666
15667        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
15668        let snapshot = self.snapshot(window, cx);
15669        let position = self.selections.newest::<Point>(cx).head();
15670        let mut row = snapshot
15671            .buffer_snapshot
15672            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15673            .find(|hunk| hunk.row_range.start.0 > position.row)
15674            .map(|hunk| hunk.row_range.start);
15675
15676        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
15677        // Outside of the project diff editor, wrap around to the beginning.
15678        if !all_diff_hunks_expanded {
15679            row = row.or_else(|| {
15680                snapshot
15681                    .buffer_snapshot
15682                    .diff_hunks_in_range(Point::zero()..position)
15683                    .find(|hunk| hunk.row_range.end.0 < position.row)
15684                    .map(|hunk| hunk.row_range.start)
15685            });
15686        }
15687
15688        if let Some(row) = row {
15689            let destination = Point::new(row.0, 0);
15690            let autoscroll = Autoscroll::center();
15691
15692            self.unfold_ranges(&[destination..destination], false, false, cx);
15693            self.change_selections(Some(autoscroll), window, cx, |s| {
15694                s.select_ranges([destination..destination]);
15695            });
15696        }
15697    }
15698
15699    fn do_stage_or_unstage(
15700        &self,
15701        stage: bool,
15702        buffer_id: BufferId,
15703        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
15704        cx: &mut App,
15705    ) -> Option<()> {
15706        let project = self.project.as_ref()?;
15707        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
15708        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
15709        let buffer_snapshot = buffer.read(cx).snapshot();
15710        let file_exists = buffer_snapshot
15711            .file()
15712            .is_some_and(|file| file.disk_state().exists());
15713        diff.update(cx, |diff, cx| {
15714            diff.stage_or_unstage_hunks(
15715                stage,
15716                &hunks
15717                    .map(|hunk| buffer_diff::DiffHunk {
15718                        buffer_range: hunk.buffer_range,
15719                        diff_base_byte_range: hunk.diff_base_byte_range,
15720                        secondary_status: hunk.secondary_status,
15721                        range: Point::zero()..Point::zero(), // unused
15722                    })
15723                    .collect::<Vec<_>>(),
15724                &buffer_snapshot,
15725                file_exists,
15726                cx,
15727            )
15728        });
15729        None
15730    }
15731
15732    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
15733        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
15734        self.buffer
15735            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
15736    }
15737
15738    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
15739        self.buffer.update(cx, |buffer, cx| {
15740            let ranges = vec![Anchor::min()..Anchor::max()];
15741            if !buffer.all_diff_hunks_expanded()
15742                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
15743            {
15744                buffer.collapse_diff_hunks(ranges, cx);
15745                true
15746            } else {
15747                false
15748            }
15749        })
15750    }
15751
15752    fn toggle_diff_hunks_in_ranges(
15753        &mut self,
15754        ranges: Vec<Range<Anchor>>,
15755        cx: &mut Context<Editor>,
15756    ) {
15757        self.buffer.update(cx, |buffer, cx| {
15758            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
15759            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
15760        })
15761    }
15762
15763    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
15764        self.buffer.update(cx, |buffer, cx| {
15765            let snapshot = buffer.snapshot(cx);
15766            let excerpt_id = range.end.excerpt_id;
15767            let point_range = range.to_point(&snapshot);
15768            let expand = !buffer.single_hunk_is_expanded(range, cx);
15769            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
15770        })
15771    }
15772
15773    pub(crate) fn apply_all_diff_hunks(
15774        &mut self,
15775        _: &ApplyAllDiffHunks,
15776        window: &mut Window,
15777        cx: &mut Context<Self>,
15778    ) {
15779        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15780
15781        let buffers = self.buffer.read(cx).all_buffers();
15782        for branch_buffer in buffers {
15783            branch_buffer.update(cx, |branch_buffer, cx| {
15784                branch_buffer.merge_into_base(Vec::new(), cx);
15785            });
15786        }
15787
15788        if let Some(project) = self.project.clone() {
15789            self.save(true, project, window, cx).detach_and_log_err(cx);
15790        }
15791    }
15792
15793    pub(crate) fn apply_selected_diff_hunks(
15794        &mut self,
15795        _: &ApplyDiffHunk,
15796        window: &mut Window,
15797        cx: &mut Context<Self>,
15798    ) {
15799        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15800        let snapshot = self.snapshot(window, cx);
15801        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
15802        let mut ranges_by_buffer = HashMap::default();
15803        self.transact(window, cx, |editor, _window, cx| {
15804            for hunk in hunks {
15805                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
15806                    ranges_by_buffer
15807                        .entry(buffer.clone())
15808                        .or_insert_with(Vec::new)
15809                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
15810                }
15811            }
15812
15813            for (buffer, ranges) in ranges_by_buffer {
15814                buffer.update(cx, |buffer, cx| {
15815                    buffer.merge_into_base(ranges, cx);
15816                });
15817            }
15818        });
15819
15820        if let Some(project) = self.project.clone() {
15821            self.save(true, project, window, cx).detach_and_log_err(cx);
15822        }
15823    }
15824
15825    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
15826        if hovered != self.gutter_hovered {
15827            self.gutter_hovered = hovered;
15828            cx.notify();
15829        }
15830    }
15831
15832    pub fn insert_blocks(
15833        &mut self,
15834        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
15835        autoscroll: Option<Autoscroll>,
15836        cx: &mut Context<Self>,
15837    ) -> Vec<CustomBlockId> {
15838        let blocks = self
15839            .display_map
15840            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
15841        if let Some(autoscroll) = autoscroll {
15842            self.request_autoscroll(autoscroll, cx);
15843        }
15844        cx.notify();
15845        blocks
15846    }
15847
15848    pub fn resize_blocks(
15849        &mut self,
15850        heights: HashMap<CustomBlockId, u32>,
15851        autoscroll: Option<Autoscroll>,
15852        cx: &mut Context<Self>,
15853    ) {
15854        self.display_map
15855            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
15856        if let Some(autoscroll) = autoscroll {
15857            self.request_autoscroll(autoscroll, cx);
15858        }
15859        cx.notify();
15860    }
15861
15862    pub fn replace_blocks(
15863        &mut self,
15864        renderers: HashMap<CustomBlockId, RenderBlock>,
15865        autoscroll: Option<Autoscroll>,
15866        cx: &mut Context<Self>,
15867    ) {
15868        self.display_map
15869            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
15870        if let Some(autoscroll) = autoscroll {
15871            self.request_autoscroll(autoscroll, cx);
15872        }
15873        cx.notify();
15874    }
15875
15876    pub fn remove_blocks(
15877        &mut self,
15878        block_ids: HashSet<CustomBlockId>,
15879        autoscroll: Option<Autoscroll>,
15880        cx: &mut Context<Self>,
15881    ) {
15882        self.display_map.update(cx, |display_map, cx| {
15883            display_map.remove_blocks(block_ids, cx)
15884        });
15885        if let Some(autoscroll) = autoscroll {
15886            self.request_autoscroll(autoscroll, cx);
15887        }
15888        cx.notify();
15889    }
15890
15891    pub fn row_for_block(
15892        &self,
15893        block_id: CustomBlockId,
15894        cx: &mut Context<Self>,
15895    ) -> Option<DisplayRow> {
15896        self.display_map
15897            .update(cx, |map, cx| map.row_for_block(block_id, cx))
15898    }
15899
15900    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
15901        self.focused_block = Some(focused_block);
15902    }
15903
15904    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
15905        self.focused_block.take()
15906    }
15907
15908    pub fn insert_creases(
15909        &mut self,
15910        creases: impl IntoIterator<Item = Crease<Anchor>>,
15911        cx: &mut Context<Self>,
15912    ) -> Vec<CreaseId> {
15913        self.display_map
15914            .update(cx, |map, cx| map.insert_creases(creases, cx))
15915    }
15916
15917    pub fn remove_creases(
15918        &mut self,
15919        ids: impl IntoIterator<Item = CreaseId>,
15920        cx: &mut Context<Self>,
15921    ) {
15922        self.display_map
15923            .update(cx, |map, cx| map.remove_creases(ids, cx));
15924    }
15925
15926    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
15927        self.display_map
15928            .update(cx, |map, cx| map.snapshot(cx))
15929            .longest_row()
15930    }
15931
15932    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
15933        self.display_map
15934            .update(cx, |map, cx| map.snapshot(cx))
15935            .max_point()
15936    }
15937
15938    pub fn text(&self, cx: &App) -> String {
15939        self.buffer.read(cx).read(cx).text()
15940    }
15941
15942    pub fn is_empty(&self, cx: &App) -> bool {
15943        self.buffer.read(cx).read(cx).is_empty()
15944    }
15945
15946    pub fn text_option(&self, cx: &App) -> Option<String> {
15947        let text = self.text(cx);
15948        let text = text.trim();
15949
15950        if text.is_empty() {
15951            return None;
15952        }
15953
15954        Some(text.to_string())
15955    }
15956
15957    pub fn set_text(
15958        &mut self,
15959        text: impl Into<Arc<str>>,
15960        window: &mut Window,
15961        cx: &mut Context<Self>,
15962    ) {
15963        self.transact(window, cx, |this, _, cx| {
15964            this.buffer
15965                .read(cx)
15966                .as_singleton()
15967                .expect("you can only call set_text on editors for singleton buffers")
15968                .update(cx, |buffer, cx| buffer.set_text(text, cx));
15969        });
15970    }
15971
15972    pub fn display_text(&self, cx: &mut App) -> String {
15973        self.display_map
15974            .update(cx, |map, cx| map.snapshot(cx))
15975            .text()
15976    }
15977
15978    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
15979        let mut wrap_guides = smallvec::smallvec![];
15980
15981        if self.show_wrap_guides == Some(false) {
15982            return wrap_guides;
15983        }
15984
15985        let settings = self.buffer.read(cx).language_settings(cx);
15986        if settings.show_wrap_guides {
15987            match self.soft_wrap_mode(cx) {
15988                SoftWrap::Column(soft_wrap) => {
15989                    wrap_guides.push((soft_wrap as usize, true));
15990                }
15991                SoftWrap::Bounded(soft_wrap) => {
15992                    wrap_guides.push((soft_wrap as usize, true));
15993                }
15994                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
15995            }
15996            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
15997        }
15998
15999        wrap_guides
16000    }
16001
16002    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
16003        let settings = self.buffer.read(cx).language_settings(cx);
16004        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
16005        match mode {
16006            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
16007                SoftWrap::None
16008            }
16009            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
16010            language_settings::SoftWrap::PreferredLineLength => {
16011                SoftWrap::Column(settings.preferred_line_length)
16012            }
16013            language_settings::SoftWrap::Bounded => {
16014                SoftWrap::Bounded(settings.preferred_line_length)
16015            }
16016        }
16017    }
16018
16019    pub fn set_soft_wrap_mode(
16020        &mut self,
16021        mode: language_settings::SoftWrap,
16022
16023        cx: &mut Context<Self>,
16024    ) {
16025        self.soft_wrap_mode_override = Some(mode);
16026        cx.notify();
16027    }
16028
16029    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
16030        self.hard_wrap = hard_wrap;
16031        cx.notify();
16032    }
16033
16034    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
16035        self.text_style_refinement = Some(style);
16036    }
16037
16038    /// called by the Element so we know what style we were most recently rendered with.
16039    pub(crate) fn set_style(
16040        &mut self,
16041        style: EditorStyle,
16042        window: &mut Window,
16043        cx: &mut Context<Self>,
16044    ) {
16045        let rem_size = window.rem_size();
16046        self.display_map.update(cx, |map, cx| {
16047            map.set_font(
16048                style.text.font(),
16049                style.text.font_size.to_pixels(rem_size),
16050                cx,
16051            )
16052        });
16053        self.style = Some(style);
16054    }
16055
16056    pub fn style(&self) -> Option<&EditorStyle> {
16057        self.style.as_ref()
16058    }
16059
16060    // Called by the element. This method is not designed to be called outside of the editor
16061    // element's layout code because it does not notify when rewrapping is computed synchronously.
16062    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
16063        self.display_map
16064            .update(cx, |map, cx| map.set_wrap_width(width, cx))
16065    }
16066
16067    pub fn set_soft_wrap(&mut self) {
16068        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
16069    }
16070
16071    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
16072        if self.soft_wrap_mode_override.is_some() {
16073            self.soft_wrap_mode_override.take();
16074        } else {
16075            let soft_wrap = match self.soft_wrap_mode(cx) {
16076                SoftWrap::GitDiff => return,
16077                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
16078                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
16079                    language_settings::SoftWrap::None
16080                }
16081            };
16082            self.soft_wrap_mode_override = Some(soft_wrap);
16083        }
16084        cx.notify();
16085    }
16086
16087    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
16088        let Some(workspace) = self.workspace() else {
16089            return;
16090        };
16091        let fs = workspace.read(cx).app_state().fs.clone();
16092        let current_show = TabBarSettings::get_global(cx).show;
16093        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
16094            setting.show = Some(!current_show);
16095        });
16096    }
16097
16098    pub fn toggle_indent_guides(
16099        &mut self,
16100        _: &ToggleIndentGuides,
16101        _: &mut Window,
16102        cx: &mut Context<Self>,
16103    ) {
16104        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
16105            self.buffer
16106                .read(cx)
16107                .language_settings(cx)
16108                .indent_guides
16109                .enabled
16110        });
16111        self.show_indent_guides = Some(!currently_enabled);
16112        cx.notify();
16113    }
16114
16115    fn should_show_indent_guides(&self) -> Option<bool> {
16116        self.show_indent_guides
16117    }
16118
16119    pub fn toggle_line_numbers(
16120        &mut self,
16121        _: &ToggleLineNumbers,
16122        _: &mut Window,
16123        cx: &mut Context<Self>,
16124    ) {
16125        let mut editor_settings = EditorSettings::get_global(cx).clone();
16126        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
16127        EditorSettings::override_global(editor_settings, cx);
16128    }
16129
16130    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
16131        if let Some(show_line_numbers) = self.show_line_numbers {
16132            return show_line_numbers;
16133        }
16134        EditorSettings::get_global(cx).gutter.line_numbers
16135    }
16136
16137    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
16138        self.use_relative_line_numbers
16139            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
16140    }
16141
16142    pub fn toggle_relative_line_numbers(
16143        &mut self,
16144        _: &ToggleRelativeLineNumbers,
16145        _: &mut Window,
16146        cx: &mut Context<Self>,
16147    ) {
16148        let is_relative = self.should_use_relative_line_numbers(cx);
16149        self.set_relative_line_number(Some(!is_relative), cx)
16150    }
16151
16152    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
16153        self.use_relative_line_numbers = is_relative;
16154        cx.notify();
16155    }
16156
16157    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
16158        self.show_gutter = show_gutter;
16159        cx.notify();
16160    }
16161
16162    pub fn set_show_scrollbars(&mut self, show_scrollbars: bool, cx: &mut Context<Self>) {
16163        self.show_scrollbars = show_scrollbars;
16164        cx.notify();
16165    }
16166
16167    pub fn disable_scrolling(&mut self, cx: &mut Context<Self>) {
16168        self.disable_scrolling = true;
16169        cx.notify();
16170    }
16171
16172    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
16173        self.show_line_numbers = Some(show_line_numbers);
16174        cx.notify();
16175    }
16176
16177    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
16178        self.disable_expand_excerpt_buttons = true;
16179        cx.notify();
16180    }
16181
16182    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
16183        self.show_git_diff_gutter = Some(show_git_diff_gutter);
16184        cx.notify();
16185    }
16186
16187    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
16188        self.show_code_actions = Some(show_code_actions);
16189        cx.notify();
16190    }
16191
16192    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
16193        self.show_runnables = Some(show_runnables);
16194        cx.notify();
16195    }
16196
16197    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
16198        self.show_breakpoints = Some(show_breakpoints);
16199        cx.notify();
16200    }
16201
16202    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
16203        if self.display_map.read(cx).masked != masked {
16204            self.display_map.update(cx, |map, _| map.masked = masked);
16205        }
16206        cx.notify()
16207    }
16208
16209    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
16210        self.show_wrap_guides = Some(show_wrap_guides);
16211        cx.notify();
16212    }
16213
16214    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
16215        self.show_indent_guides = Some(show_indent_guides);
16216        cx.notify();
16217    }
16218
16219    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
16220        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
16221            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
16222                if let Some(dir) = file.abs_path(cx).parent() {
16223                    return Some(dir.to_owned());
16224                }
16225            }
16226
16227            if let Some(project_path) = buffer.read(cx).project_path(cx) {
16228                return Some(project_path.path.to_path_buf());
16229            }
16230        }
16231
16232        None
16233    }
16234
16235    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
16236        self.active_excerpt(cx)?
16237            .1
16238            .read(cx)
16239            .file()
16240            .and_then(|f| f.as_local())
16241    }
16242
16243    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
16244        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
16245            let buffer = buffer.read(cx);
16246            if let Some(project_path) = buffer.project_path(cx) {
16247                let project = self.project.as_ref()?.read(cx);
16248                project.absolute_path(&project_path, cx)
16249            } else {
16250                buffer
16251                    .file()
16252                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
16253            }
16254        })
16255    }
16256
16257    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
16258        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
16259            let project_path = buffer.read(cx).project_path(cx)?;
16260            let project = self.project.as_ref()?.read(cx);
16261            let entry = project.entry_for_path(&project_path, cx)?;
16262            let path = entry.path.to_path_buf();
16263            Some(path)
16264        })
16265    }
16266
16267    pub fn reveal_in_finder(
16268        &mut self,
16269        _: &RevealInFileManager,
16270        _window: &mut Window,
16271        cx: &mut Context<Self>,
16272    ) {
16273        if let Some(target) = self.target_file(cx) {
16274            cx.reveal_path(&target.abs_path(cx));
16275        }
16276    }
16277
16278    pub fn copy_path(
16279        &mut self,
16280        _: &zed_actions::workspace::CopyPath,
16281        _window: &mut Window,
16282        cx: &mut Context<Self>,
16283    ) {
16284        if let Some(path) = self.target_file_abs_path(cx) {
16285            if let Some(path) = path.to_str() {
16286                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
16287            }
16288        }
16289    }
16290
16291    pub fn copy_relative_path(
16292        &mut self,
16293        _: &zed_actions::workspace::CopyRelativePath,
16294        _window: &mut Window,
16295        cx: &mut Context<Self>,
16296    ) {
16297        if let Some(path) = self.target_file_path(cx) {
16298            if let Some(path) = path.to_str() {
16299                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
16300            }
16301        }
16302    }
16303
16304    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
16305        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
16306            buffer.read(cx).project_path(cx)
16307        } else {
16308            None
16309        }
16310    }
16311
16312    // Returns true if the editor handled a go-to-line request
16313    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
16314        maybe!({
16315            let breakpoint_store = self.breakpoint_store.as_ref()?;
16316
16317            let Some((_, _, active_position)) =
16318                breakpoint_store.read(cx).active_position().cloned()
16319            else {
16320                self.clear_row_highlights::<DebugCurrentRowHighlight>();
16321                return None;
16322            };
16323
16324            let snapshot = self
16325                .project
16326                .as_ref()?
16327                .read(cx)
16328                .buffer_for_id(active_position.buffer_id?, cx)?
16329                .read(cx)
16330                .snapshot();
16331
16332            let mut handled = false;
16333            for (id, ExcerptRange { context, .. }) in self
16334                .buffer
16335                .read(cx)
16336                .excerpts_for_buffer(active_position.buffer_id?, cx)
16337            {
16338                if context.start.cmp(&active_position, &snapshot).is_ge()
16339                    || context.end.cmp(&active_position, &snapshot).is_lt()
16340                {
16341                    continue;
16342                }
16343                let snapshot = self.buffer.read(cx).snapshot(cx);
16344                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, active_position)?;
16345
16346                handled = true;
16347                self.clear_row_highlights::<DebugCurrentRowHighlight>();
16348                self.go_to_line::<DebugCurrentRowHighlight>(
16349                    multibuffer_anchor,
16350                    Some(cx.theme().colors().editor_debugger_active_line_background),
16351                    window,
16352                    cx,
16353                );
16354
16355                cx.notify();
16356            }
16357            handled.then_some(())
16358        })
16359        .is_some()
16360    }
16361
16362    pub fn copy_file_name_without_extension(
16363        &mut self,
16364        _: &CopyFileNameWithoutExtension,
16365        _: &mut Window,
16366        cx: &mut Context<Self>,
16367    ) {
16368        if let Some(file) = self.target_file(cx) {
16369            if let Some(file_stem) = file.path().file_stem() {
16370                if let Some(name) = file_stem.to_str() {
16371                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
16372                }
16373            }
16374        }
16375    }
16376
16377    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
16378        if let Some(file) = self.target_file(cx) {
16379            if let Some(file_name) = file.path().file_name() {
16380                if let Some(name) = file_name.to_str() {
16381                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
16382                }
16383            }
16384        }
16385    }
16386
16387    pub fn toggle_git_blame(
16388        &mut self,
16389        _: &::git::Blame,
16390        window: &mut Window,
16391        cx: &mut Context<Self>,
16392    ) {
16393        self.show_git_blame_gutter = !self.show_git_blame_gutter;
16394
16395        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
16396            self.start_git_blame(true, window, cx);
16397        }
16398
16399        cx.notify();
16400    }
16401
16402    pub fn toggle_git_blame_inline(
16403        &mut self,
16404        _: &ToggleGitBlameInline,
16405        window: &mut Window,
16406        cx: &mut Context<Self>,
16407    ) {
16408        self.toggle_git_blame_inline_internal(true, window, cx);
16409        cx.notify();
16410    }
16411
16412    pub fn open_git_blame_commit(
16413        &mut self,
16414        _: &OpenGitBlameCommit,
16415        window: &mut Window,
16416        cx: &mut Context<Self>,
16417    ) {
16418        self.open_git_blame_commit_internal(window, cx);
16419    }
16420
16421    fn open_git_blame_commit_internal(
16422        &mut self,
16423        window: &mut Window,
16424        cx: &mut Context<Self>,
16425    ) -> Option<()> {
16426        let blame = self.blame.as_ref()?;
16427        let snapshot = self.snapshot(window, cx);
16428        let cursor = self.selections.newest::<Point>(cx).head();
16429        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
16430        let blame_entry = blame
16431            .update(cx, |blame, cx| {
16432                blame
16433                    .blame_for_rows(
16434                        &[RowInfo {
16435                            buffer_id: Some(buffer.remote_id()),
16436                            buffer_row: Some(point.row),
16437                            ..Default::default()
16438                        }],
16439                        cx,
16440                    )
16441                    .next()
16442            })
16443            .flatten()?;
16444        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
16445        let repo = blame.read(cx).repository(cx)?;
16446        let workspace = self.workspace()?.downgrade();
16447        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
16448        None
16449    }
16450
16451    pub fn git_blame_inline_enabled(&self) -> bool {
16452        self.git_blame_inline_enabled
16453    }
16454
16455    pub fn toggle_selection_menu(
16456        &mut self,
16457        _: &ToggleSelectionMenu,
16458        _: &mut Window,
16459        cx: &mut Context<Self>,
16460    ) {
16461        self.show_selection_menu = self
16462            .show_selection_menu
16463            .map(|show_selections_menu| !show_selections_menu)
16464            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
16465
16466        cx.notify();
16467    }
16468
16469    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
16470        self.show_selection_menu
16471            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
16472    }
16473
16474    fn start_git_blame(
16475        &mut self,
16476        user_triggered: bool,
16477        window: &mut Window,
16478        cx: &mut Context<Self>,
16479    ) {
16480        if let Some(project) = self.project.as_ref() {
16481            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
16482                return;
16483            };
16484
16485            if buffer.read(cx).file().is_none() {
16486                return;
16487            }
16488
16489            let focused = self.focus_handle(cx).contains_focused(window, cx);
16490
16491            let project = project.clone();
16492            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
16493            self.blame_subscription =
16494                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
16495            self.blame = Some(blame);
16496        }
16497    }
16498
16499    fn toggle_git_blame_inline_internal(
16500        &mut self,
16501        user_triggered: bool,
16502        window: &mut Window,
16503        cx: &mut Context<Self>,
16504    ) {
16505        if self.git_blame_inline_enabled {
16506            self.git_blame_inline_enabled = false;
16507            self.show_git_blame_inline = false;
16508            self.show_git_blame_inline_delay_task.take();
16509        } else {
16510            self.git_blame_inline_enabled = true;
16511            self.start_git_blame_inline(user_triggered, window, cx);
16512        }
16513
16514        cx.notify();
16515    }
16516
16517    fn start_git_blame_inline(
16518        &mut self,
16519        user_triggered: bool,
16520        window: &mut Window,
16521        cx: &mut Context<Self>,
16522    ) {
16523        self.start_git_blame(user_triggered, window, cx);
16524
16525        if ProjectSettings::get_global(cx)
16526            .git
16527            .inline_blame_delay()
16528            .is_some()
16529        {
16530            self.start_inline_blame_timer(window, cx);
16531        } else {
16532            self.show_git_blame_inline = true
16533        }
16534    }
16535
16536    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
16537        self.blame.as_ref()
16538    }
16539
16540    pub fn show_git_blame_gutter(&self) -> bool {
16541        self.show_git_blame_gutter
16542    }
16543
16544    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
16545        self.show_git_blame_gutter && self.has_blame_entries(cx)
16546    }
16547
16548    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
16549        self.show_git_blame_inline
16550            && (self.focus_handle.is_focused(window)
16551                || self
16552                    .git_blame_inline_tooltip
16553                    .as_ref()
16554                    .and_then(|t| t.upgrade())
16555                    .is_some())
16556            && !self.newest_selection_head_on_empty_line(cx)
16557            && self.has_blame_entries(cx)
16558    }
16559
16560    fn has_blame_entries(&self, cx: &App) -> bool {
16561        self.blame()
16562            .map_or(false, |blame| blame.read(cx).has_generated_entries())
16563    }
16564
16565    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
16566        let cursor_anchor = self.selections.newest_anchor().head();
16567
16568        let snapshot = self.buffer.read(cx).snapshot(cx);
16569        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
16570
16571        snapshot.line_len(buffer_row) == 0
16572    }
16573
16574    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
16575        let buffer_and_selection = maybe!({
16576            let selection = self.selections.newest::<Point>(cx);
16577            let selection_range = selection.range();
16578
16579            let multi_buffer = self.buffer().read(cx);
16580            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16581            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
16582
16583            let (buffer, range, _) = if selection.reversed {
16584                buffer_ranges.first()
16585            } else {
16586                buffer_ranges.last()
16587            }?;
16588
16589            let selection = text::ToPoint::to_point(&range.start, &buffer).row
16590                ..text::ToPoint::to_point(&range.end, &buffer).row;
16591            Some((
16592                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
16593                selection,
16594            ))
16595        });
16596
16597        let Some((buffer, selection)) = buffer_and_selection else {
16598            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
16599        };
16600
16601        let Some(project) = self.project.as_ref() else {
16602            return Task::ready(Err(anyhow!("editor does not have project")));
16603        };
16604
16605        project.update(cx, |project, cx| {
16606            project.get_permalink_to_line(&buffer, selection, cx)
16607        })
16608    }
16609
16610    pub fn copy_permalink_to_line(
16611        &mut self,
16612        _: &CopyPermalinkToLine,
16613        window: &mut Window,
16614        cx: &mut Context<Self>,
16615    ) {
16616        let permalink_task = self.get_permalink_to_line(cx);
16617        let workspace = self.workspace();
16618
16619        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
16620            Ok(permalink) => {
16621                cx.update(|_, cx| {
16622                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
16623                })
16624                .ok();
16625            }
16626            Err(err) => {
16627                let message = format!("Failed to copy permalink: {err}");
16628
16629                Err::<(), anyhow::Error>(err).log_err();
16630
16631                if let Some(workspace) = workspace {
16632                    workspace
16633                        .update_in(cx, |workspace, _, cx| {
16634                            struct CopyPermalinkToLine;
16635
16636                            workspace.show_toast(
16637                                Toast::new(
16638                                    NotificationId::unique::<CopyPermalinkToLine>(),
16639                                    message,
16640                                ),
16641                                cx,
16642                            )
16643                        })
16644                        .ok();
16645                }
16646            }
16647        })
16648        .detach();
16649    }
16650
16651    pub fn copy_file_location(
16652        &mut self,
16653        _: &CopyFileLocation,
16654        _: &mut Window,
16655        cx: &mut Context<Self>,
16656    ) {
16657        let selection = self.selections.newest::<Point>(cx).start.row + 1;
16658        if let Some(file) = self.target_file(cx) {
16659            if let Some(path) = file.path().to_str() {
16660                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
16661            }
16662        }
16663    }
16664
16665    pub fn open_permalink_to_line(
16666        &mut self,
16667        _: &OpenPermalinkToLine,
16668        window: &mut Window,
16669        cx: &mut Context<Self>,
16670    ) {
16671        let permalink_task = self.get_permalink_to_line(cx);
16672        let workspace = self.workspace();
16673
16674        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
16675            Ok(permalink) => {
16676                cx.update(|_, cx| {
16677                    cx.open_url(permalink.as_ref());
16678                })
16679                .ok();
16680            }
16681            Err(err) => {
16682                let message = format!("Failed to open permalink: {err}");
16683
16684                Err::<(), anyhow::Error>(err).log_err();
16685
16686                if let Some(workspace) = workspace {
16687                    workspace
16688                        .update(cx, |workspace, cx| {
16689                            struct OpenPermalinkToLine;
16690
16691                            workspace.show_toast(
16692                                Toast::new(
16693                                    NotificationId::unique::<OpenPermalinkToLine>(),
16694                                    message,
16695                                ),
16696                                cx,
16697                            )
16698                        })
16699                        .ok();
16700                }
16701            }
16702        })
16703        .detach();
16704    }
16705
16706    pub fn insert_uuid_v4(
16707        &mut self,
16708        _: &InsertUuidV4,
16709        window: &mut Window,
16710        cx: &mut Context<Self>,
16711    ) {
16712        self.insert_uuid(UuidVersion::V4, window, cx);
16713    }
16714
16715    pub fn insert_uuid_v7(
16716        &mut self,
16717        _: &InsertUuidV7,
16718        window: &mut Window,
16719        cx: &mut Context<Self>,
16720    ) {
16721        self.insert_uuid(UuidVersion::V7, window, cx);
16722    }
16723
16724    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
16725        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16726        self.transact(window, cx, |this, window, cx| {
16727            let edits = this
16728                .selections
16729                .all::<Point>(cx)
16730                .into_iter()
16731                .map(|selection| {
16732                    let uuid = match version {
16733                        UuidVersion::V4 => uuid::Uuid::new_v4(),
16734                        UuidVersion::V7 => uuid::Uuid::now_v7(),
16735                    };
16736
16737                    (selection.range(), uuid.to_string())
16738                });
16739            this.edit(edits, cx);
16740            this.refresh_inline_completion(true, false, window, cx);
16741        });
16742    }
16743
16744    pub fn open_selections_in_multibuffer(
16745        &mut self,
16746        _: &OpenSelectionsInMultibuffer,
16747        window: &mut Window,
16748        cx: &mut Context<Self>,
16749    ) {
16750        let multibuffer = self.buffer.read(cx);
16751
16752        let Some(buffer) = multibuffer.as_singleton() else {
16753            return;
16754        };
16755
16756        let Some(workspace) = self.workspace() else {
16757            return;
16758        };
16759
16760        let locations = self
16761            .selections
16762            .disjoint_anchors()
16763            .iter()
16764            .map(|range| Location {
16765                buffer: buffer.clone(),
16766                range: range.start.text_anchor..range.end.text_anchor,
16767            })
16768            .collect::<Vec<_>>();
16769
16770        let title = multibuffer.title(cx).to_string();
16771
16772        cx.spawn_in(window, async move |_, cx| {
16773            workspace.update_in(cx, |workspace, window, cx| {
16774                Self::open_locations_in_multibuffer(
16775                    workspace,
16776                    locations,
16777                    format!("Selections for '{title}'"),
16778                    false,
16779                    MultibufferSelectionMode::All,
16780                    window,
16781                    cx,
16782                );
16783            })
16784        })
16785        .detach();
16786    }
16787
16788    /// Adds a row highlight for the given range. If a row has multiple highlights, the
16789    /// last highlight added will be used.
16790    ///
16791    /// If the range ends at the beginning of a line, then that line will not be highlighted.
16792    pub fn highlight_rows<T: 'static>(
16793        &mut self,
16794        range: Range<Anchor>,
16795        color: Hsla,
16796        should_autoscroll: bool,
16797        cx: &mut Context<Self>,
16798    ) {
16799        let snapshot = self.buffer().read(cx).snapshot(cx);
16800        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
16801        let ix = row_highlights.binary_search_by(|highlight| {
16802            Ordering::Equal
16803                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
16804                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
16805        });
16806
16807        if let Err(mut ix) = ix {
16808            let index = post_inc(&mut self.highlight_order);
16809
16810            // If this range intersects with the preceding highlight, then merge it with
16811            // the preceding highlight. Otherwise insert a new highlight.
16812            let mut merged = false;
16813            if ix > 0 {
16814                let prev_highlight = &mut row_highlights[ix - 1];
16815                if prev_highlight
16816                    .range
16817                    .end
16818                    .cmp(&range.start, &snapshot)
16819                    .is_ge()
16820                {
16821                    ix -= 1;
16822                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
16823                        prev_highlight.range.end = range.end;
16824                    }
16825                    merged = true;
16826                    prev_highlight.index = index;
16827                    prev_highlight.color = color;
16828                    prev_highlight.should_autoscroll = should_autoscroll;
16829                }
16830            }
16831
16832            if !merged {
16833                row_highlights.insert(
16834                    ix,
16835                    RowHighlight {
16836                        range: range.clone(),
16837                        index,
16838                        color,
16839                        should_autoscroll,
16840                    },
16841                );
16842            }
16843
16844            // If any of the following highlights intersect with this one, merge them.
16845            while let Some(next_highlight) = row_highlights.get(ix + 1) {
16846                let highlight = &row_highlights[ix];
16847                if next_highlight
16848                    .range
16849                    .start
16850                    .cmp(&highlight.range.end, &snapshot)
16851                    .is_le()
16852                {
16853                    if next_highlight
16854                        .range
16855                        .end
16856                        .cmp(&highlight.range.end, &snapshot)
16857                        .is_gt()
16858                    {
16859                        row_highlights[ix].range.end = next_highlight.range.end;
16860                    }
16861                    row_highlights.remove(ix + 1);
16862                } else {
16863                    break;
16864                }
16865            }
16866        }
16867    }
16868
16869    /// Remove any highlighted row ranges of the given type that intersect the
16870    /// given ranges.
16871    pub fn remove_highlighted_rows<T: 'static>(
16872        &mut self,
16873        ranges_to_remove: Vec<Range<Anchor>>,
16874        cx: &mut Context<Self>,
16875    ) {
16876        let snapshot = self.buffer().read(cx).snapshot(cx);
16877        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
16878        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
16879        row_highlights.retain(|highlight| {
16880            while let Some(range_to_remove) = ranges_to_remove.peek() {
16881                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
16882                    Ordering::Less | Ordering::Equal => {
16883                        ranges_to_remove.next();
16884                    }
16885                    Ordering::Greater => {
16886                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
16887                            Ordering::Less | Ordering::Equal => {
16888                                return false;
16889                            }
16890                            Ordering::Greater => break,
16891                        }
16892                    }
16893                }
16894            }
16895
16896            true
16897        })
16898    }
16899
16900    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
16901    pub fn clear_row_highlights<T: 'static>(&mut self) {
16902        self.highlighted_rows.remove(&TypeId::of::<T>());
16903    }
16904
16905    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
16906    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
16907        self.highlighted_rows
16908            .get(&TypeId::of::<T>())
16909            .map_or(&[] as &[_], |vec| vec.as_slice())
16910            .iter()
16911            .map(|highlight| (highlight.range.clone(), highlight.color))
16912    }
16913
16914    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
16915    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
16916    /// Allows to ignore certain kinds of highlights.
16917    pub fn highlighted_display_rows(
16918        &self,
16919        window: &mut Window,
16920        cx: &mut App,
16921    ) -> BTreeMap<DisplayRow, LineHighlight> {
16922        let snapshot = self.snapshot(window, cx);
16923        let mut used_highlight_orders = HashMap::default();
16924        self.highlighted_rows
16925            .iter()
16926            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
16927            .fold(
16928                BTreeMap::<DisplayRow, LineHighlight>::new(),
16929                |mut unique_rows, highlight| {
16930                    let start = highlight.range.start.to_display_point(&snapshot);
16931                    let end = highlight.range.end.to_display_point(&snapshot);
16932                    let start_row = start.row().0;
16933                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
16934                        && end.column() == 0
16935                    {
16936                        end.row().0.saturating_sub(1)
16937                    } else {
16938                        end.row().0
16939                    };
16940                    for row in start_row..=end_row {
16941                        let used_index =
16942                            used_highlight_orders.entry(row).or_insert(highlight.index);
16943                        if highlight.index >= *used_index {
16944                            *used_index = highlight.index;
16945                            unique_rows.insert(DisplayRow(row), highlight.color.into());
16946                        }
16947                    }
16948                    unique_rows
16949                },
16950            )
16951    }
16952
16953    pub fn highlighted_display_row_for_autoscroll(
16954        &self,
16955        snapshot: &DisplaySnapshot,
16956    ) -> Option<DisplayRow> {
16957        self.highlighted_rows
16958            .values()
16959            .flat_map(|highlighted_rows| highlighted_rows.iter())
16960            .filter_map(|highlight| {
16961                if highlight.should_autoscroll {
16962                    Some(highlight.range.start.to_display_point(snapshot).row())
16963                } else {
16964                    None
16965                }
16966            })
16967            .min()
16968    }
16969
16970    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
16971        self.highlight_background::<SearchWithinRange>(
16972            ranges,
16973            |colors| colors.editor_document_highlight_read_background,
16974            cx,
16975        )
16976    }
16977
16978    pub fn set_breadcrumb_header(&mut self, new_header: String) {
16979        self.breadcrumb_header = Some(new_header);
16980    }
16981
16982    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
16983        self.clear_background_highlights::<SearchWithinRange>(cx);
16984    }
16985
16986    pub fn highlight_background<T: 'static>(
16987        &mut self,
16988        ranges: &[Range<Anchor>],
16989        color_fetcher: fn(&ThemeColors) -> Hsla,
16990        cx: &mut Context<Self>,
16991    ) {
16992        self.background_highlights
16993            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
16994        self.scrollbar_marker_state.dirty = true;
16995        cx.notify();
16996    }
16997
16998    pub fn clear_background_highlights<T: 'static>(
16999        &mut self,
17000        cx: &mut Context<Self>,
17001    ) -> Option<BackgroundHighlight> {
17002        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
17003        if !text_highlights.1.is_empty() {
17004            self.scrollbar_marker_state.dirty = true;
17005            cx.notify();
17006        }
17007        Some(text_highlights)
17008    }
17009
17010    pub fn highlight_gutter<T: 'static>(
17011        &mut self,
17012        ranges: &[Range<Anchor>],
17013        color_fetcher: fn(&App) -> Hsla,
17014        cx: &mut Context<Self>,
17015    ) {
17016        self.gutter_highlights
17017            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17018        cx.notify();
17019    }
17020
17021    pub fn clear_gutter_highlights<T: 'static>(
17022        &mut self,
17023        cx: &mut Context<Self>,
17024    ) -> Option<GutterHighlight> {
17025        cx.notify();
17026        self.gutter_highlights.remove(&TypeId::of::<T>())
17027    }
17028
17029    #[cfg(feature = "test-support")]
17030    pub fn all_text_background_highlights(
17031        &self,
17032        window: &mut Window,
17033        cx: &mut Context<Self>,
17034    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17035        let snapshot = self.snapshot(window, cx);
17036        let buffer = &snapshot.buffer_snapshot;
17037        let start = buffer.anchor_before(0);
17038        let end = buffer.anchor_after(buffer.len());
17039        let theme = cx.theme().colors();
17040        self.background_highlights_in_range(start..end, &snapshot, theme)
17041    }
17042
17043    #[cfg(feature = "test-support")]
17044    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
17045        let snapshot = self.buffer().read(cx).snapshot(cx);
17046
17047        let highlights = self
17048            .background_highlights
17049            .get(&TypeId::of::<items::BufferSearchHighlights>());
17050
17051        if let Some((_color, ranges)) = highlights {
17052            ranges
17053                .iter()
17054                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
17055                .collect_vec()
17056        } else {
17057            vec![]
17058        }
17059    }
17060
17061    fn document_highlights_for_position<'a>(
17062        &'a self,
17063        position: Anchor,
17064        buffer: &'a MultiBufferSnapshot,
17065    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
17066        let read_highlights = self
17067            .background_highlights
17068            .get(&TypeId::of::<DocumentHighlightRead>())
17069            .map(|h| &h.1);
17070        let write_highlights = self
17071            .background_highlights
17072            .get(&TypeId::of::<DocumentHighlightWrite>())
17073            .map(|h| &h.1);
17074        let left_position = position.bias_left(buffer);
17075        let right_position = position.bias_right(buffer);
17076        read_highlights
17077            .into_iter()
17078            .chain(write_highlights)
17079            .flat_map(move |ranges| {
17080                let start_ix = match ranges.binary_search_by(|probe| {
17081                    let cmp = probe.end.cmp(&left_position, buffer);
17082                    if cmp.is_ge() {
17083                        Ordering::Greater
17084                    } else {
17085                        Ordering::Less
17086                    }
17087                }) {
17088                    Ok(i) | Err(i) => i,
17089                };
17090
17091                ranges[start_ix..]
17092                    .iter()
17093                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
17094            })
17095    }
17096
17097    pub fn has_background_highlights<T: 'static>(&self) -> bool {
17098        self.background_highlights
17099            .get(&TypeId::of::<T>())
17100            .map_or(false, |(_, highlights)| !highlights.is_empty())
17101    }
17102
17103    pub fn background_highlights_in_range(
17104        &self,
17105        search_range: Range<Anchor>,
17106        display_snapshot: &DisplaySnapshot,
17107        theme: &ThemeColors,
17108    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17109        let mut results = Vec::new();
17110        for (color_fetcher, ranges) in self.background_highlights.values() {
17111            let color = color_fetcher(theme);
17112            let start_ix = match ranges.binary_search_by(|probe| {
17113                let cmp = probe
17114                    .end
17115                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17116                if cmp.is_gt() {
17117                    Ordering::Greater
17118                } else {
17119                    Ordering::Less
17120                }
17121            }) {
17122                Ok(i) | Err(i) => i,
17123            };
17124            for range in &ranges[start_ix..] {
17125                if range
17126                    .start
17127                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17128                    .is_ge()
17129                {
17130                    break;
17131                }
17132
17133                let start = range.start.to_display_point(display_snapshot);
17134                let end = range.end.to_display_point(display_snapshot);
17135                results.push((start..end, color))
17136            }
17137        }
17138        results
17139    }
17140
17141    pub fn background_highlight_row_ranges<T: 'static>(
17142        &self,
17143        search_range: Range<Anchor>,
17144        display_snapshot: &DisplaySnapshot,
17145        count: usize,
17146    ) -> Vec<RangeInclusive<DisplayPoint>> {
17147        let mut results = Vec::new();
17148        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
17149            return vec![];
17150        };
17151
17152        let start_ix = match ranges.binary_search_by(|probe| {
17153            let cmp = probe
17154                .end
17155                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17156            if cmp.is_gt() {
17157                Ordering::Greater
17158            } else {
17159                Ordering::Less
17160            }
17161        }) {
17162            Ok(i) | Err(i) => i,
17163        };
17164        let mut push_region = |start: Option<Point>, end: Option<Point>| {
17165            if let (Some(start_display), Some(end_display)) = (start, end) {
17166                results.push(
17167                    start_display.to_display_point(display_snapshot)
17168                        ..=end_display.to_display_point(display_snapshot),
17169                );
17170            }
17171        };
17172        let mut start_row: Option<Point> = None;
17173        let mut end_row: Option<Point> = None;
17174        if ranges.len() > count {
17175            return Vec::new();
17176        }
17177        for range in &ranges[start_ix..] {
17178            if range
17179                .start
17180                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17181                .is_ge()
17182            {
17183                break;
17184            }
17185            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
17186            if let Some(current_row) = &end_row {
17187                if end.row == current_row.row {
17188                    continue;
17189                }
17190            }
17191            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
17192            if start_row.is_none() {
17193                assert_eq!(end_row, None);
17194                start_row = Some(start);
17195                end_row = Some(end);
17196                continue;
17197            }
17198            if let Some(current_end) = end_row.as_mut() {
17199                if start.row > current_end.row + 1 {
17200                    push_region(start_row, end_row);
17201                    start_row = Some(start);
17202                    end_row = Some(end);
17203                } else {
17204                    // Merge two hunks.
17205                    *current_end = end;
17206                }
17207            } else {
17208                unreachable!();
17209            }
17210        }
17211        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
17212        push_region(start_row, end_row);
17213        results
17214    }
17215
17216    pub fn gutter_highlights_in_range(
17217        &self,
17218        search_range: Range<Anchor>,
17219        display_snapshot: &DisplaySnapshot,
17220        cx: &App,
17221    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17222        let mut results = Vec::new();
17223        for (color_fetcher, ranges) in self.gutter_highlights.values() {
17224            let color = color_fetcher(cx);
17225            let start_ix = match ranges.binary_search_by(|probe| {
17226                let cmp = probe
17227                    .end
17228                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17229                if cmp.is_gt() {
17230                    Ordering::Greater
17231                } else {
17232                    Ordering::Less
17233                }
17234            }) {
17235                Ok(i) | Err(i) => i,
17236            };
17237            for range in &ranges[start_ix..] {
17238                if range
17239                    .start
17240                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17241                    .is_ge()
17242                {
17243                    break;
17244                }
17245
17246                let start = range.start.to_display_point(display_snapshot);
17247                let end = range.end.to_display_point(display_snapshot);
17248                results.push((start..end, color))
17249            }
17250        }
17251        results
17252    }
17253
17254    /// Get the text ranges corresponding to the redaction query
17255    pub fn redacted_ranges(
17256        &self,
17257        search_range: Range<Anchor>,
17258        display_snapshot: &DisplaySnapshot,
17259        cx: &App,
17260    ) -> Vec<Range<DisplayPoint>> {
17261        display_snapshot
17262            .buffer_snapshot
17263            .redacted_ranges(search_range, |file| {
17264                if let Some(file) = file {
17265                    file.is_private()
17266                        && EditorSettings::get(
17267                            Some(SettingsLocation {
17268                                worktree_id: file.worktree_id(cx),
17269                                path: file.path().as_ref(),
17270                            }),
17271                            cx,
17272                        )
17273                        .redact_private_values
17274                } else {
17275                    false
17276                }
17277            })
17278            .map(|range| {
17279                range.start.to_display_point(display_snapshot)
17280                    ..range.end.to_display_point(display_snapshot)
17281            })
17282            .collect()
17283    }
17284
17285    pub fn highlight_text<T: 'static>(
17286        &mut self,
17287        ranges: Vec<Range<Anchor>>,
17288        style: HighlightStyle,
17289        cx: &mut Context<Self>,
17290    ) {
17291        self.display_map.update(cx, |map, _| {
17292            map.highlight_text(TypeId::of::<T>(), ranges, style)
17293        });
17294        cx.notify();
17295    }
17296
17297    pub(crate) fn highlight_inlays<T: 'static>(
17298        &mut self,
17299        highlights: Vec<InlayHighlight>,
17300        style: HighlightStyle,
17301        cx: &mut Context<Self>,
17302    ) {
17303        self.display_map.update(cx, |map, _| {
17304            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
17305        });
17306        cx.notify();
17307    }
17308
17309    pub fn text_highlights<'a, T: 'static>(
17310        &'a self,
17311        cx: &'a App,
17312    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
17313        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
17314    }
17315
17316    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
17317        let cleared = self
17318            .display_map
17319            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
17320        if cleared {
17321            cx.notify();
17322        }
17323    }
17324
17325    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
17326        (self.read_only(cx) || self.blink_manager.read(cx).visible())
17327            && self.focus_handle.is_focused(window)
17328    }
17329
17330    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
17331        self.show_cursor_when_unfocused = is_enabled;
17332        cx.notify();
17333    }
17334
17335    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
17336        cx.notify();
17337    }
17338
17339    fn on_buffer_event(
17340        &mut self,
17341        multibuffer: &Entity<MultiBuffer>,
17342        event: &multi_buffer::Event,
17343        window: &mut Window,
17344        cx: &mut Context<Self>,
17345    ) {
17346        match event {
17347            multi_buffer::Event::Edited {
17348                singleton_buffer_edited,
17349                edited_buffer: buffer_edited,
17350            } => {
17351                self.scrollbar_marker_state.dirty = true;
17352                self.active_indent_guides_state.dirty = true;
17353                self.refresh_active_diagnostics(cx);
17354                self.refresh_code_actions(window, cx);
17355                if self.has_active_inline_completion() {
17356                    self.update_visible_inline_completion(window, cx);
17357                }
17358                if let Some(buffer) = buffer_edited {
17359                    let buffer_id = buffer.read(cx).remote_id();
17360                    if !self.registered_buffers.contains_key(&buffer_id) {
17361                        if let Some(project) = self.project.as_ref() {
17362                            project.update(cx, |project, cx| {
17363                                self.registered_buffers.insert(
17364                                    buffer_id,
17365                                    project.register_buffer_with_language_servers(&buffer, cx),
17366                                );
17367                            })
17368                        }
17369                    }
17370                }
17371                cx.emit(EditorEvent::BufferEdited);
17372                cx.emit(SearchEvent::MatchesInvalidated);
17373                if *singleton_buffer_edited {
17374                    if let Some(project) = &self.project {
17375                        #[allow(clippy::mutable_key_type)]
17376                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
17377                            multibuffer
17378                                .all_buffers()
17379                                .into_iter()
17380                                .filter_map(|buffer| {
17381                                    buffer.update(cx, |buffer, cx| {
17382                                        let language = buffer.language()?;
17383                                        let should_discard = project.update(cx, |project, cx| {
17384                                            project.is_local()
17385                                                && !project.has_language_servers_for(buffer, cx)
17386                                        });
17387                                        should_discard.not().then_some(language.clone())
17388                                    })
17389                                })
17390                                .collect::<HashSet<_>>()
17391                        });
17392                        if !languages_affected.is_empty() {
17393                            self.refresh_inlay_hints(
17394                                InlayHintRefreshReason::BufferEdited(languages_affected),
17395                                cx,
17396                            );
17397                        }
17398                    }
17399                }
17400
17401                let Some(project) = &self.project else { return };
17402                let (telemetry, is_via_ssh) = {
17403                    let project = project.read(cx);
17404                    let telemetry = project.client().telemetry().clone();
17405                    let is_via_ssh = project.is_via_ssh();
17406                    (telemetry, is_via_ssh)
17407                };
17408                refresh_linked_ranges(self, window, cx);
17409                telemetry.log_edit_event("editor", is_via_ssh);
17410            }
17411            multi_buffer::Event::ExcerptsAdded {
17412                buffer,
17413                predecessor,
17414                excerpts,
17415            } => {
17416                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
17417                let buffer_id = buffer.read(cx).remote_id();
17418                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
17419                    if let Some(project) = &self.project {
17420                        get_uncommitted_diff_for_buffer(
17421                            project,
17422                            [buffer.clone()],
17423                            self.buffer.clone(),
17424                            cx,
17425                        )
17426                        .detach();
17427                    }
17428                }
17429                cx.emit(EditorEvent::ExcerptsAdded {
17430                    buffer: buffer.clone(),
17431                    predecessor: *predecessor,
17432                    excerpts: excerpts.clone(),
17433                });
17434                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17435            }
17436            multi_buffer::Event::ExcerptsRemoved { ids } => {
17437                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
17438                let buffer = self.buffer.read(cx);
17439                self.registered_buffers
17440                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
17441                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
17442                cx.emit(EditorEvent::ExcerptsRemoved { ids: ids.clone() })
17443            }
17444            multi_buffer::Event::ExcerptsEdited {
17445                excerpt_ids,
17446                buffer_ids,
17447            } => {
17448                self.display_map.update(cx, |map, cx| {
17449                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
17450                });
17451                cx.emit(EditorEvent::ExcerptsEdited {
17452                    ids: excerpt_ids.clone(),
17453                })
17454            }
17455            multi_buffer::Event::ExcerptsExpanded { ids } => {
17456                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17457                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
17458            }
17459            multi_buffer::Event::Reparsed(buffer_id) => {
17460                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
17461                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
17462
17463                cx.emit(EditorEvent::Reparsed(*buffer_id));
17464            }
17465            multi_buffer::Event::DiffHunksToggled => {
17466                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
17467            }
17468            multi_buffer::Event::LanguageChanged(buffer_id) => {
17469                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
17470                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
17471                cx.emit(EditorEvent::Reparsed(*buffer_id));
17472                cx.notify();
17473            }
17474            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
17475            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
17476            multi_buffer::Event::FileHandleChanged
17477            | multi_buffer::Event::Reloaded
17478            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
17479            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
17480            multi_buffer::Event::DiagnosticsUpdated => {
17481                self.refresh_active_diagnostics(cx);
17482                self.refresh_inline_diagnostics(true, window, cx);
17483                self.scrollbar_marker_state.dirty = true;
17484                cx.notify();
17485            }
17486            _ => {}
17487        };
17488    }
17489
17490    fn on_display_map_changed(
17491        &mut self,
17492        _: Entity<DisplayMap>,
17493        _: &mut Window,
17494        cx: &mut Context<Self>,
17495    ) {
17496        cx.notify();
17497    }
17498
17499    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17500        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
17501        self.update_edit_prediction_settings(cx);
17502        self.refresh_inline_completion(true, false, window, cx);
17503        self.refresh_inlay_hints(
17504            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
17505                self.selections.newest_anchor().head(),
17506                &self.buffer.read(cx).snapshot(cx),
17507                cx,
17508            )),
17509            cx,
17510        );
17511
17512        let old_cursor_shape = self.cursor_shape;
17513
17514        {
17515            let editor_settings = EditorSettings::get_global(cx);
17516            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
17517            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
17518            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
17519            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
17520        }
17521
17522        if old_cursor_shape != self.cursor_shape {
17523            cx.emit(EditorEvent::CursorShapeChanged);
17524        }
17525
17526        let project_settings = ProjectSettings::get_global(cx);
17527        self.serialize_dirty_buffers = project_settings.session.restore_unsaved_buffers;
17528
17529        if self.mode.is_full() {
17530            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
17531            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
17532            if self.show_inline_diagnostics != show_inline_diagnostics {
17533                self.show_inline_diagnostics = show_inline_diagnostics;
17534                self.refresh_inline_diagnostics(false, window, cx);
17535            }
17536
17537            if self.git_blame_inline_enabled != inline_blame_enabled {
17538                self.toggle_git_blame_inline_internal(false, window, cx);
17539            }
17540        }
17541
17542        cx.notify();
17543    }
17544
17545    pub fn set_searchable(&mut self, searchable: bool) {
17546        self.searchable = searchable;
17547    }
17548
17549    pub fn searchable(&self) -> bool {
17550        self.searchable
17551    }
17552
17553    fn open_proposed_changes_editor(
17554        &mut self,
17555        _: &OpenProposedChangesEditor,
17556        window: &mut Window,
17557        cx: &mut Context<Self>,
17558    ) {
17559        let Some(workspace) = self.workspace() else {
17560            cx.propagate();
17561            return;
17562        };
17563
17564        let selections = self.selections.all::<usize>(cx);
17565        let multi_buffer = self.buffer.read(cx);
17566        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17567        let mut new_selections_by_buffer = HashMap::default();
17568        for selection in selections {
17569            for (buffer, range, _) in
17570                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
17571            {
17572                let mut range = range.to_point(buffer);
17573                range.start.column = 0;
17574                range.end.column = buffer.line_len(range.end.row);
17575                new_selections_by_buffer
17576                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
17577                    .or_insert(Vec::new())
17578                    .push(range)
17579            }
17580        }
17581
17582        let proposed_changes_buffers = new_selections_by_buffer
17583            .into_iter()
17584            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
17585            .collect::<Vec<_>>();
17586        let proposed_changes_editor = cx.new(|cx| {
17587            ProposedChangesEditor::new(
17588                "Proposed changes",
17589                proposed_changes_buffers,
17590                self.project.clone(),
17591                window,
17592                cx,
17593            )
17594        });
17595
17596        window.defer(cx, move |window, cx| {
17597            workspace.update(cx, |workspace, cx| {
17598                workspace.active_pane().update(cx, |pane, cx| {
17599                    pane.add_item(
17600                        Box::new(proposed_changes_editor),
17601                        true,
17602                        true,
17603                        None,
17604                        window,
17605                        cx,
17606                    );
17607                });
17608            });
17609        });
17610    }
17611
17612    pub fn open_excerpts_in_split(
17613        &mut self,
17614        _: &OpenExcerptsSplit,
17615        window: &mut Window,
17616        cx: &mut Context<Self>,
17617    ) {
17618        self.open_excerpts_common(None, true, window, cx)
17619    }
17620
17621    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
17622        self.open_excerpts_common(None, false, window, cx)
17623    }
17624
17625    fn open_excerpts_common(
17626        &mut self,
17627        jump_data: Option<JumpData>,
17628        split: bool,
17629        window: &mut Window,
17630        cx: &mut Context<Self>,
17631    ) {
17632        let Some(workspace) = self.workspace() else {
17633            cx.propagate();
17634            return;
17635        };
17636
17637        if self.buffer.read(cx).is_singleton() {
17638            cx.propagate();
17639            return;
17640        }
17641
17642        let mut new_selections_by_buffer = HashMap::default();
17643        match &jump_data {
17644            Some(JumpData::MultiBufferPoint {
17645                excerpt_id,
17646                position,
17647                anchor,
17648                line_offset_from_top,
17649            }) => {
17650                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17651                if let Some(buffer) = multi_buffer_snapshot
17652                    .buffer_id_for_excerpt(*excerpt_id)
17653                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
17654                {
17655                    let buffer_snapshot = buffer.read(cx).snapshot();
17656                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
17657                        language::ToPoint::to_point(anchor, &buffer_snapshot)
17658                    } else {
17659                        buffer_snapshot.clip_point(*position, Bias::Left)
17660                    };
17661                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
17662                    new_selections_by_buffer.insert(
17663                        buffer,
17664                        (
17665                            vec![jump_to_offset..jump_to_offset],
17666                            Some(*line_offset_from_top),
17667                        ),
17668                    );
17669                }
17670            }
17671            Some(JumpData::MultiBufferRow {
17672                row,
17673                line_offset_from_top,
17674            }) => {
17675                let point = MultiBufferPoint::new(row.0, 0);
17676                if let Some((buffer, buffer_point, _)) =
17677                    self.buffer.read(cx).point_to_buffer_point(point, cx)
17678                {
17679                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
17680                    new_selections_by_buffer
17681                        .entry(buffer)
17682                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
17683                        .0
17684                        .push(buffer_offset..buffer_offset)
17685                }
17686            }
17687            None => {
17688                let selections = self.selections.all::<usize>(cx);
17689                let multi_buffer = self.buffer.read(cx);
17690                for selection in selections {
17691                    for (snapshot, range, _, anchor) in multi_buffer
17692                        .snapshot(cx)
17693                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
17694                    {
17695                        if let Some(anchor) = anchor {
17696                            // selection is in a deleted hunk
17697                            let Some(buffer_id) = anchor.buffer_id else {
17698                                continue;
17699                            };
17700                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
17701                                continue;
17702                            };
17703                            let offset = text::ToOffset::to_offset(
17704                                &anchor.text_anchor,
17705                                &buffer_handle.read(cx).snapshot(),
17706                            );
17707                            let range = offset..offset;
17708                            new_selections_by_buffer
17709                                .entry(buffer_handle)
17710                                .or_insert((Vec::new(), None))
17711                                .0
17712                                .push(range)
17713                        } else {
17714                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
17715                            else {
17716                                continue;
17717                            };
17718                            new_selections_by_buffer
17719                                .entry(buffer_handle)
17720                                .or_insert((Vec::new(), None))
17721                                .0
17722                                .push(range)
17723                        }
17724                    }
17725                }
17726            }
17727        }
17728
17729        new_selections_by_buffer
17730            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
17731
17732        if new_selections_by_buffer.is_empty() {
17733            return;
17734        }
17735
17736        // We defer the pane interaction because we ourselves are a workspace item
17737        // and activating a new item causes the pane to call a method on us reentrantly,
17738        // which panics if we're on the stack.
17739        window.defer(cx, move |window, cx| {
17740            workspace.update(cx, |workspace, cx| {
17741                let pane = if split {
17742                    workspace.adjacent_pane(window, cx)
17743                } else {
17744                    workspace.active_pane().clone()
17745                };
17746
17747                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
17748                    let editor = buffer
17749                        .read(cx)
17750                        .file()
17751                        .is_none()
17752                        .then(|| {
17753                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
17754                            // so `workspace.open_project_item` will never find them, always opening a new editor.
17755                            // Instead, we try to activate the existing editor in the pane first.
17756                            let (editor, pane_item_index) =
17757                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
17758                                    let editor = item.downcast::<Editor>()?;
17759                                    let singleton_buffer =
17760                                        editor.read(cx).buffer().read(cx).as_singleton()?;
17761                                    if singleton_buffer == buffer {
17762                                        Some((editor, i))
17763                                    } else {
17764                                        None
17765                                    }
17766                                })?;
17767                            pane.update(cx, |pane, cx| {
17768                                pane.activate_item(pane_item_index, true, true, window, cx)
17769                            });
17770                            Some(editor)
17771                        })
17772                        .flatten()
17773                        .unwrap_or_else(|| {
17774                            workspace.open_project_item::<Self>(
17775                                pane.clone(),
17776                                buffer,
17777                                true,
17778                                true,
17779                                window,
17780                                cx,
17781                            )
17782                        });
17783
17784                    editor.update(cx, |editor, cx| {
17785                        let autoscroll = match scroll_offset {
17786                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
17787                            None => Autoscroll::newest(),
17788                        };
17789                        let nav_history = editor.nav_history.take();
17790                        editor.change_selections(Some(autoscroll), window, cx, |s| {
17791                            s.select_ranges(ranges);
17792                        });
17793                        editor.nav_history = nav_history;
17794                    });
17795                }
17796            })
17797        });
17798    }
17799
17800    // For now, don't allow opening excerpts in buffers that aren't backed by
17801    // regular project files.
17802    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
17803        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
17804    }
17805
17806    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
17807        let snapshot = self.buffer.read(cx).read(cx);
17808        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
17809        Some(
17810            ranges
17811                .iter()
17812                .map(move |range| {
17813                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
17814                })
17815                .collect(),
17816        )
17817    }
17818
17819    fn selection_replacement_ranges(
17820        &self,
17821        range: Range<OffsetUtf16>,
17822        cx: &mut App,
17823    ) -> Vec<Range<OffsetUtf16>> {
17824        let selections = self.selections.all::<OffsetUtf16>(cx);
17825        let newest_selection = selections
17826            .iter()
17827            .max_by_key(|selection| selection.id)
17828            .unwrap();
17829        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
17830        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
17831        let snapshot = self.buffer.read(cx).read(cx);
17832        selections
17833            .into_iter()
17834            .map(|mut selection| {
17835                selection.start.0 =
17836                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
17837                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
17838                snapshot.clip_offset_utf16(selection.start, Bias::Left)
17839                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
17840            })
17841            .collect()
17842    }
17843
17844    fn report_editor_event(
17845        &self,
17846        event_type: &'static str,
17847        file_extension: Option<String>,
17848        cx: &App,
17849    ) {
17850        if cfg!(any(test, feature = "test-support")) {
17851            return;
17852        }
17853
17854        let Some(project) = &self.project else { return };
17855
17856        // If None, we are in a file without an extension
17857        let file = self
17858            .buffer
17859            .read(cx)
17860            .as_singleton()
17861            .and_then(|b| b.read(cx).file());
17862        let file_extension = file_extension.or(file
17863            .as_ref()
17864            .and_then(|file| Path::new(file.file_name(cx)).extension())
17865            .and_then(|e| e.to_str())
17866            .map(|a| a.to_string()));
17867
17868        let vim_mode = vim_enabled(cx);
17869
17870        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
17871        let copilot_enabled = edit_predictions_provider
17872            == language::language_settings::EditPredictionProvider::Copilot;
17873        let copilot_enabled_for_language = self
17874            .buffer
17875            .read(cx)
17876            .language_settings(cx)
17877            .show_edit_predictions;
17878
17879        let project = project.read(cx);
17880        telemetry::event!(
17881            event_type,
17882            file_extension,
17883            vim_mode,
17884            copilot_enabled,
17885            copilot_enabled_for_language,
17886            edit_predictions_provider,
17887            is_via_ssh = project.is_via_ssh(),
17888        );
17889    }
17890
17891    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
17892    /// with each line being an array of {text, highlight} objects.
17893    fn copy_highlight_json(
17894        &mut self,
17895        _: &CopyHighlightJson,
17896        window: &mut Window,
17897        cx: &mut Context<Self>,
17898    ) {
17899        #[derive(Serialize)]
17900        struct Chunk<'a> {
17901            text: String,
17902            highlight: Option<&'a str>,
17903        }
17904
17905        let snapshot = self.buffer.read(cx).snapshot(cx);
17906        let range = self
17907            .selected_text_range(false, window, cx)
17908            .and_then(|selection| {
17909                if selection.range.is_empty() {
17910                    None
17911                } else {
17912                    Some(selection.range)
17913                }
17914            })
17915            .unwrap_or_else(|| 0..snapshot.len());
17916
17917        let chunks = snapshot.chunks(range, true);
17918        let mut lines = Vec::new();
17919        let mut line: VecDeque<Chunk> = VecDeque::new();
17920
17921        let Some(style) = self.style.as_ref() else {
17922            return;
17923        };
17924
17925        for chunk in chunks {
17926            let highlight = chunk
17927                .syntax_highlight_id
17928                .and_then(|id| id.name(&style.syntax));
17929            let mut chunk_lines = chunk.text.split('\n').peekable();
17930            while let Some(text) = chunk_lines.next() {
17931                let mut merged_with_last_token = false;
17932                if let Some(last_token) = line.back_mut() {
17933                    if last_token.highlight == highlight {
17934                        last_token.text.push_str(text);
17935                        merged_with_last_token = true;
17936                    }
17937                }
17938
17939                if !merged_with_last_token {
17940                    line.push_back(Chunk {
17941                        text: text.into(),
17942                        highlight,
17943                    });
17944                }
17945
17946                if chunk_lines.peek().is_some() {
17947                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
17948                        line.pop_front();
17949                    }
17950                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
17951                        line.pop_back();
17952                    }
17953
17954                    lines.push(mem::take(&mut line));
17955                }
17956            }
17957        }
17958
17959        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
17960            return;
17961        };
17962        cx.write_to_clipboard(ClipboardItem::new_string(lines));
17963    }
17964
17965    pub fn open_context_menu(
17966        &mut self,
17967        _: &OpenContextMenu,
17968        window: &mut Window,
17969        cx: &mut Context<Self>,
17970    ) {
17971        self.request_autoscroll(Autoscroll::newest(), cx);
17972        let position = self.selections.newest_display(cx).start;
17973        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
17974    }
17975
17976    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
17977        &self.inlay_hint_cache
17978    }
17979
17980    pub fn replay_insert_event(
17981        &mut self,
17982        text: &str,
17983        relative_utf16_range: Option<Range<isize>>,
17984        window: &mut Window,
17985        cx: &mut Context<Self>,
17986    ) {
17987        if !self.input_enabled {
17988            cx.emit(EditorEvent::InputIgnored { text: text.into() });
17989            return;
17990        }
17991        if let Some(relative_utf16_range) = relative_utf16_range {
17992            let selections = self.selections.all::<OffsetUtf16>(cx);
17993            self.change_selections(None, window, cx, |s| {
17994                let new_ranges = selections.into_iter().map(|range| {
17995                    let start = OffsetUtf16(
17996                        range
17997                            .head()
17998                            .0
17999                            .saturating_add_signed(relative_utf16_range.start),
18000                    );
18001                    let end = OffsetUtf16(
18002                        range
18003                            .head()
18004                            .0
18005                            .saturating_add_signed(relative_utf16_range.end),
18006                    );
18007                    start..end
18008                });
18009                s.select_ranges(new_ranges);
18010            });
18011        }
18012
18013        self.handle_input(text, window, cx);
18014    }
18015
18016    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
18017        let Some(provider) = self.semantics_provider.as_ref() else {
18018            return false;
18019        };
18020
18021        let mut supports = false;
18022        self.buffer().update(cx, |this, cx| {
18023            this.for_each_buffer(|buffer| {
18024                supports |= provider.supports_inlay_hints(buffer, cx);
18025            });
18026        });
18027
18028        supports
18029    }
18030
18031    pub fn is_focused(&self, window: &Window) -> bool {
18032        self.focus_handle.is_focused(window)
18033    }
18034
18035    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18036        cx.emit(EditorEvent::Focused);
18037
18038        if let Some(descendant) = self
18039            .last_focused_descendant
18040            .take()
18041            .and_then(|descendant| descendant.upgrade())
18042        {
18043            window.focus(&descendant);
18044        } else {
18045            if let Some(blame) = self.blame.as_ref() {
18046                blame.update(cx, GitBlame::focus)
18047            }
18048
18049            self.blink_manager.update(cx, BlinkManager::enable);
18050            self.show_cursor_names(window, cx);
18051            self.buffer.update(cx, |buffer, cx| {
18052                buffer.finalize_last_transaction(cx);
18053                if self.leader_peer_id.is_none() {
18054                    buffer.set_active_selections(
18055                        &self.selections.disjoint_anchors(),
18056                        self.selections.line_mode,
18057                        self.cursor_shape,
18058                        cx,
18059                    );
18060                }
18061            });
18062        }
18063    }
18064
18065    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
18066        cx.emit(EditorEvent::FocusedIn)
18067    }
18068
18069    fn handle_focus_out(
18070        &mut self,
18071        event: FocusOutEvent,
18072        _window: &mut Window,
18073        cx: &mut Context<Self>,
18074    ) {
18075        if event.blurred != self.focus_handle {
18076            self.last_focused_descendant = Some(event.blurred);
18077        }
18078        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
18079    }
18080
18081    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18082        self.blink_manager.update(cx, BlinkManager::disable);
18083        self.buffer
18084            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
18085
18086        if let Some(blame) = self.blame.as_ref() {
18087            blame.update(cx, GitBlame::blur)
18088        }
18089        if !self.hover_state.focused(window, cx) {
18090            hide_hover(self, cx);
18091        }
18092        if !self
18093            .context_menu
18094            .borrow()
18095            .as_ref()
18096            .is_some_and(|context_menu| context_menu.focused(window, cx))
18097        {
18098            self.hide_context_menu(window, cx);
18099        }
18100        self.discard_inline_completion(false, cx);
18101        cx.emit(EditorEvent::Blurred);
18102        cx.notify();
18103    }
18104
18105    pub fn register_action<A: Action>(
18106        &mut self,
18107        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
18108    ) -> Subscription {
18109        let id = self.next_editor_action_id.post_inc();
18110        let listener = Arc::new(listener);
18111        self.editor_actions.borrow_mut().insert(
18112            id,
18113            Box::new(move |window, _| {
18114                let listener = listener.clone();
18115                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
18116                    let action = action.downcast_ref().unwrap();
18117                    if phase == DispatchPhase::Bubble {
18118                        listener(action, window, cx)
18119                    }
18120                })
18121            }),
18122        );
18123
18124        let editor_actions = self.editor_actions.clone();
18125        Subscription::new(move || {
18126            editor_actions.borrow_mut().remove(&id);
18127        })
18128    }
18129
18130    pub fn file_header_size(&self) -> u32 {
18131        FILE_HEADER_HEIGHT
18132    }
18133
18134    pub fn restore(
18135        &mut self,
18136        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
18137        window: &mut Window,
18138        cx: &mut Context<Self>,
18139    ) {
18140        let workspace = self.workspace();
18141        let project = self.project.as_ref();
18142        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
18143            let mut tasks = Vec::new();
18144            for (buffer_id, changes) in revert_changes {
18145                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
18146                    buffer.update(cx, |buffer, cx| {
18147                        buffer.edit(
18148                            changes
18149                                .into_iter()
18150                                .map(|(range, text)| (range, text.to_string())),
18151                            None,
18152                            cx,
18153                        );
18154                    });
18155
18156                    if let Some(project) =
18157                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
18158                    {
18159                        project.update(cx, |project, cx| {
18160                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
18161                        })
18162                    }
18163                }
18164            }
18165            tasks
18166        });
18167        cx.spawn_in(window, async move |_, cx| {
18168            for (buffer, task) in save_tasks {
18169                let result = task.await;
18170                if result.is_err() {
18171                    let Some(path) = buffer
18172                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
18173                        .ok()
18174                    else {
18175                        continue;
18176                    };
18177                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
18178                        let Some(task) = cx
18179                            .update_window_entity(&workspace, |workspace, window, cx| {
18180                                workspace
18181                                    .open_path_preview(path, None, false, false, false, window, cx)
18182                            })
18183                            .ok()
18184                        else {
18185                            continue;
18186                        };
18187                        task.await.log_err();
18188                    }
18189                }
18190            }
18191        })
18192        .detach();
18193        self.change_selections(None, window, cx, |selections| selections.refresh());
18194    }
18195
18196    pub fn to_pixel_point(
18197        &self,
18198        source: multi_buffer::Anchor,
18199        editor_snapshot: &EditorSnapshot,
18200        window: &mut Window,
18201    ) -> Option<gpui::Point<Pixels>> {
18202        let source_point = source.to_display_point(editor_snapshot);
18203        self.display_to_pixel_point(source_point, editor_snapshot, window)
18204    }
18205
18206    pub fn display_to_pixel_point(
18207        &self,
18208        source: DisplayPoint,
18209        editor_snapshot: &EditorSnapshot,
18210        window: &mut Window,
18211    ) -> Option<gpui::Point<Pixels>> {
18212        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
18213        let text_layout_details = self.text_layout_details(window);
18214        let scroll_top = text_layout_details
18215            .scroll_anchor
18216            .scroll_position(editor_snapshot)
18217            .y;
18218
18219        if source.row().as_f32() < scroll_top.floor() {
18220            return None;
18221        }
18222        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
18223        let source_y = line_height * (source.row().as_f32() - scroll_top);
18224        Some(gpui::Point::new(source_x, source_y))
18225    }
18226
18227    pub fn has_visible_completions_menu(&self) -> bool {
18228        !self.edit_prediction_preview_is_active()
18229            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
18230                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
18231            })
18232    }
18233
18234    pub fn register_addon<T: Addon>(&mut self, instance: T) {
18235        self.addons
18236            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
18237    }
18238
18239    pub fn unregister_addon<T: Addon>(&mut self) {
18240        self.addons.remove(&std::any::TypeId::of::<T>());
18241    }
18242
18243    pub fn addon<T: Addon>(&self) -> Option<&T> {
18244        let type_id = std::any::TypeId::of::<T>();
18245        self.addons
18246            .get(&type_id)
18247            .and_then(|item| item.to_any().downcast_ref::<T>())
18248    }
18249
18250    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
18251        let text_layout_details = self.text_layout_details(window);
18252        let style = &text_layout_details.editor_style;
18253        let font_id = window.text_system().resolve_font(&style.text.font());
18254        let font_size = style.text.font_size.to_pixels(window.rem_size());
18255        let line_height = style.text.line_height_in_pixels(window.rem_size());
18256        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
18257
18258        gpui::Size::new(em_width, line_height)
18259    }
18260
18261    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
18262        self.load_diff_task.clone()
18263    }
18264
18265    fn read_metadata_from_db(
18266        &mut self,
18267        item_id: u64,
18268        workspace_id: WorkspaceId,
18269        window: &mut Window,
18270        cx: &mut Context<Editor>,
18271    ) {
18272        if self.is_singleton(cx)
18273            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
18274        {
18275            let buffer_snapshot = OnceCell::new();
18276
18277            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
18278                if !folds.is_empty() {
18279                    let snapshot =
18280                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
18281                    self.fold_ranges(
18282                        folds
18283                            .into_iter()
18284                            .map(|(start, end)| {
18285                                snapshot.clip_offset(start, Bias::Left)
18286                                    ..snapshot.clip_offset(end, Bias::Right)
18287                            })
18288                            .collect(),
18289                        false,
18290                        window,
18291                        cx,
18292                    );
18293                }
18294            }
18295
18296            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
18297                if !selections.is_empty() {
18298                    let snapshot =
18299                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
18300                    self.change_selections(None, window, cx, |s| {
18301                        s.select_ranges(selections.into_iter().map(|(start, end)| {
18302                            snapshot.clip_offset(start, Bias::Left)
18303                                ..snapshot.clip_offset(end, Bias::Right)
18304                        }));
18305                    });
18306                }
18307            };
18308        }
18309
18310        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
18311    }
18312}
18313
18314fn vim_enabled(cx: &App) -> bool {
18315    cx.global::<SettingsStore>()
18316        .raw_user_settings()
18317        .get("vim_mode")
18318        == Some(&serde_json::Value::Bool(true))
18319}
18320
18321// Consider user intent and default settings
18322fn choose_completion_range(
18323    completion: &Completion,
18324    intent: CompletionIntent,
18325    buffer: &Entity<Buffer>,
18326    cx: &mut Context<Editor>,
18327) -> Range<usize> {
18328    fn should_replace(
18329        completion: &Completion,
18330        insert_range: &Range<text::Anchor>,
18331        intent: CompletionIntent,
18332        completion_mode_setting: LspInsertMode,
18333        buffer: &Buffer,
18334    ) -> bool {
18335        // specific actions take precedence over settings
18336        match intent {
18337            CompletionIntent::CompleteWithInsert => return false,
18338            CompletionIntent::CompleteWithReplace => return true,
18339            CompletionIntent::Complete | CompletionIntent::Compose => {}
18340        }
18341
18342        match completion_mode_setting {
18343            LspInsertMode::Insert => false,
18344            LspInsertMode::Replace => true,
18345            LspInsertMode::ReplaceSubsequence => {
18346                let mut text_to_replace = buffer.chars_for_range(
18347                    buffer.anchor_before(completion.replace_range.start)
18348                        ..buffer.anchor_after(completion.replace_range.end),
18349                );
18350                let mut completion_text = completion.new_text.chars();
18351
18352                // is `text_to_replace` a subsequence of `completion_text`
18353                text_to_replace
18354                    .all(|needle_ch| completion_text.any(|haystack_ch| haystack_ch == needle_ch))
18355            }
18356            LspInsertMode::ReplaceSuffix => {
18357                let range_after_cursor = insert_range.end..completion.replace_range.end;
18358
18359                let text_after_cursor = buffer
18360                    .text_for_range(
18361                        buffer.anchor_before(range_after_cursor.start)
18362                            ..buffer.anchor_after(range_after_cursor.end),
18363                    )
18364                    .collect::<String>();
18365                completion.new_text.ends_with(&text_after_cursor)
18366            }
18367        }
18368    }
18369
18370    let buffer = buffer.read(cx);
18371
18372    if let CompletionSource::Lsp {
18373        insert_range: Some(insert_range),
18374        ..
18375    } = &completion.source
18376    {
18377        let completion_mode_setting =
18378            language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
18379                .completions
18380                .lsp_insert_mode;
18381
18382        if !should_replace(
18383            completion,
18384            &insert_range,
18385            intent,
18386            completion_mode_setting,
18387            buffer,
18388        ) {
18389            return insert_range.to_offset(buffer);
18390        }
18391    }
18392
18393    completion.replace_range.to_offset(buffer)
18394}
18395
18396fn insert_extra_newline_brackets(
18397    buffer: &MultiBufferSnapshot,
18398    range: Range<usize>,
18399    language: &language::LanguageScope,
18400) -> bool {
18401    let leading_whitespace_len = buffer
18402        .reversed_chars_at(range.start)
18403        .take_while(|c| c.is_whitespace() && *c != '\n')
18404        .map(|c| c.len_utf8())
18405        .sum::<usize>();
18406    let trailing_whitespace_len = buffer
18407        .chars_at(range.end)
18408        .take_while(|c| c.is_whitespace() && *c != '\n')
18409        .map(|c| c.len_utf8())
18410        .sum::<usize>();
18411    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
18412
18413    language.brackets().any(|(pair, enabled)| {
18414        let pair_start = pair.start.trim_end();
18415        let pair_end = pair.end.trim_start();
18416
18417        enabled
18418            && pair.newline
18419            && buffer.contains_str_at(range.end, pair_end)
18420            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
18421    })
18422}
18423
18424fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
18425    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
18426        [(buffer, range, _)] => (*buffer, range.clone()),
18427        _ => return false,
18428    };
18429    let pair = {
18430        let mut result: Option<BracketMatch> = None;
18431
18432        for pair in buffer
18433            .all_bracket_ranges(range.clone())
18434            .filter(move |pair| {
18435                pair.open_range.start <= range.start && pair.close_range.end >= range.end
18436            })
18437        {
18438            let len = pair.close_range.end - pair.open_range.start;
18439
18440            if let Some(existing) = &result {
18441                let existing_len = existing.close_range.end - existing.open_range.start;
18442                if len > existing_len {
18443                    continue;
18444                }
18445            }
18446
18447            result = Some(pair);
18448        }
18449
18450        result
18451    };
18452    let Some(pair) = pair else {
18453        return false;
18454    };
18455    pair.newline_only
18456        && buffer
18457            .chars_for_range(pair.open_range.end..range.start)
18458            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
18459            .all(|c| c.is_whitespace() && c != '\n')
18460}
18461
18462fn get_uncommitted_diff_for_buffer(
18463    project: &Entity<Project>,
18464    buffers: impl IntoIterator<Item = Entity<Buffer>>,
18465    buffer: Entity<MultiBuffer>,
18466    cx: &mut App,
18467) -> Task<()> {
18468    let mut tasks = Vec::new();
18469    project.update(cx, |project, cx| {
18470        for buffer in buffers {
18471            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
18472                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
18473            }
18474        }
18475    });
18476    cx.spawn(async move |cx| {
18477        let diffs = future::join_all(tasks).await;
18478        buffer
18479            .update(cx, |buffer, cx| {
18480                for diff in diffs.into_iter().flatten() {
18481                    buffer.add_diff(diff, cx);
18482                }
18483            })
18484            .ok();
18485    })
18486}
18487
18488fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
18489    let tab_size = tab_size.get() as usize;
18490    let mut width = offset;
18491
18492    for ch in text.chars() {
18493        width += if ch == '\t' {
18494            tab_size - (width % tab_size)
18495        } else {
18496            1
18497        };
18498    }
18499
18500    width - offset
18501}
18502
18503#[cfg(test)]
18504mod tests {
18505    use super::*;
18506
18507    #[test]
18508    fn test_string_size_with_expanded_tabs() {
18509        let nz = |val| NonZeroU32::new(val).unwrap();
18510        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
18511        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
18512        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
18513        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
18514        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
18515        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
18516        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
18517        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
18518    }
18519}
18520
18521/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
18522struct WordBreakingTokenizer<'a> {
18523    input: &'a str,
18524}
18525
18526impl<'a> WordBreakingTokenizer<'a> {
18527    fn new(input: &'a str) -> Self {
18528        Self { input }
18529    }
18530}
18531
18532fn is_char_ideographic(ch: char) -> bool {
18533    use unicode_script::Script::*;
18534    use unicode_script::UnicodeScript;
18535    matches!(ch.script(), Han | Tangut | Yi)
18536}
18537
18538fn is_grapheme_ideographic(text: &str) -> bool {
18539    text.chars().any(is_char_ideographic)
18540}
18541
18542fn is_grapheme_whitespace(text: &str) -> bool {
18543    text.chars().any(|x| x.is_whitespace())
18544}
18545
18546fn should_stay_with_preceding_ideograph(text: &str) -> bool {
18547    text.chars().next().map_or(false, |ch| {
18548        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
18549    })
18550}
18551
18552#[derive(PartialEq, Eq, Debug, Clone, Copy)]
18553enum WordBreakToken<'a> {
18554    Word { token: &'a str, grapheme_len: usize },
18555    InlineWhitespace { token: &'a str, grapheme_len: usize },
18556    Newline,
18557}
18558
18559impl<'a> Iterator for WordBreakingTokenizer<'a> {
18560    /// Yields a span, the count of graphemes in the token, and whether it was
18561    /// whitespace. Note that it also breaks at word boundaries.
18562    type Item = WordBreakToken<'a>;
18563
18564    fn next(&mut self) -> Option<Self::Item> {
18565        use unicode_segmentation::UnicodeSegmentation;
18566        if self.input.is_empty() {
18567            return None;
18568        }
18569
18570        let mut iter = self.input.graphemes(true).peekable();
18571        let mut offset = 0;
18572        let mut grapheme_len = 0;
18573        if let Some(first_grapheme) = iter.next() {
18574            let is_newline = first_grapheme == "\n";
18575            let is_whitespace = is_grapheme_whitespace(first_grapheme);
18576            offset += first_grapheme.len();
18577            grapheme_len += 1;
18578            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
18579                if let Some(grapheme) = iter.peek().copied() {
18580                    if should_stay_with_preceding_ideograph(grapheme) {
18581                        offset += grapheme.len();
18582                        grapheme_len += 1;
18583                    }
18584                }
18585            } else {
18586                let mut words = self.input[offset..].split_word_bound_indices().peekable();
18587                let mut next_word_bound = words.peek().copied();
18588                if next_word_bound.map_or(false, |(i, _)| i == 0) {
18589                    next_word_bound = words.next();
18590                }
18591                while let Some(grapheme) = iter.peek().copied() {
18592                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
18593                        break;
18594                    };
18595                    if is_grapheme_whitespace(grapheme) != is_whitespace
18596                        || (grapheme == "\n") != is_newline
18597                    {
18598                        break;
18599                    };
18600                    offset += grapheme.len();
18601                    grapheme_len += 1;
18602                    iter.next();
18603                }
18604            }
18605            let token = &self.input[..offset];
18606            self.input = &self.input[offset..];
18607            if token == "\n" {
18608                Some(WordBreakToken::Newline)
18609            } else if is_whitespace {
18610                Some(WordBreakToken::InlineWhitespace {
18611                    token,
18612                    grapheme_len,
18613                })
18614            } else {
18615                Some(WordBreakToken::Word {
18616                    token,
18617                    grapheme_len,
18618                })
18619            }
18620        } else {
18621            None
18622        }
18623    }
18624}
18625
18626#[test]
18627fn test_word_breaking_tokenizer() {
18628    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
18629        ("", &[]),
18630        ("  ", &[whitespace("  ", 2)]),
18631        ("Ʒ", &[word("Ʒ", 1)]),
18632        ("Ǽ", &[word("Ǽ", 1)]),
18633        ("", &[word("", 1)]),
18634        ("⋑⋑", &[word("⋑⋑", 2)]),
18635        (
18636            "原理,进而",
18637            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
18638        ),
18639        (
18640            "hello world",
18641            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
18642        ),
18643        (
18644            "hello, world",
18645            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
18646        ),
18647        (
18648            "  hello world",
18649            &[
18650                whitespace("  ", 2),
18651                word("hello", 5),
18652                whitespace(" ", 1),
18653                word("world", 5),
18654            ],
18655        ),
18656        (
18657            "这是什么 \n 钢笔",
18658            &[
18659                word("", 1),
18660                word("", 1),
18661                word("", 1),
18662                word("", 1),
18663                whitespace(" ", 1),
18664                newline(),
18665                whitespace(" ", 1),
18666                word("", 1),
18667                word("", 1),
18668            ],
18669        ),
18670        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
18671    ];
18672
18673    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
18674        WordBreakToken::Word {
18675            token,
18676            grapheme_len,
18677        }
18678    }
18679
18680    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
18681        WordBreakToken::InlineWhitespace {
18682            token,
18683            grapheme_len,
18684        }
18685    }
18686
18687    fn newline() -> WordBreakToken<'static> {
18688        WordBreakToken::Newline
18689    }
18690
18691    for (input, result) in tests {
18692        assert_eq!(
18693            WordBreakingTokenizer::new(input)
18694                .collect::<Vec<_>>()
18695                .as_slice(),
18696            *result,
18697        );
18698    }
18699}
18700
18701fn wrap_with_prefix(
18702    line_prefix: String,
18703    unwrapped_text: String,
18704    wrap_column: usize,
18705    tab_size: NonZeroU32,
18706    preserve_existing_whitespace: bool,
18707) -> String {
18708    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
18709    let mut wrapped_text = String::new();
18710    let mut current_line = line_prefix.clone();
18711
18712    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
18713    let mut current_line_len = line_prefix_len;
18714    let mut in_whitespace = false;
18715    for token in tokenizer {
18716        let have_preceding_whitespace = in_whitespace;
18717        match token {
18718            WordBreakToken::Word {
18719                token,
18720                grapheme_len,
18721            } => {
18722                in_whitespace = false;
18723                if current_line_len + grapheme_len > wrap_column
18724                    && current_line_len != line_prefix_len
18725                {
18726                    wrapped_text.push_str(current_line.trim_end());
18727                    wrapped_text.push('\n');
18728                    current_line.truncate(line_prefix.len());
18729                    current_line_len = line_prefix_len;
18730                }
18731                current_line.push_str(token);
18732                current_line_len += grapheme_len;
18733            }
18734            WordBreakToken::InlineWhitespace {
18735                mut token,
18736                mut grapheme_len,
18737            } => {
18738                in_whitespace = true;
18739                if have_preceding_whitespace && !preserve_existing_whitespace {
18740                    continue;
18741                }
18742                if !preserve_existing_whitespace {
18743                    token = " ";
18744                    grapheme_len = 1;
18745                }
18746                if current_line_len + grapheme_len > wrap_column {
18747                    wrapped_text.push_str(current_line.trim_end());
18748                    wrapped_text.push('\n');
18749                    current_line.truncate(line_prefix.len());
18750                    current_line_len = line_prefix_len;
18751                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
18752                    current_line.push_str(token);
18753                    current_line_len += grapheme_len;
18754                }
18755            }
18756            WordBreakToken::Newline => {
18757                in_whitespace = true;
18758                if preserve_existing_whitespace {
18759                    wrapped_text.push_str(current_line.trim_end());
18760                    wrapped_text.push('\n');
18761                    current_line.truncate(line_prefix.len());
18762                    current_line_len = line_prefix_len;
18763                } else if have_preceding_whitespace {
18764                    continue;
18765                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
18766                {
18767                    wrapped_text.push_str(current_line.trim_end());
18768                    wrapped_text.push('\n');
18769                    current_line.truncate(line_prefix.len());
18770                    current_line_len = line_prefix_len;
18771                } else if current_line_len != line_prefix_len {
18772                    current_line.push(' ');
18773                    current_line_len += 1;
18774                }
18775            }
18776        }
18777    }
18778
18779    if !current_line.is_empty() {
18780        wrapped_text.push_str(&current_line);
18781    }
18782    wrapped_text
18783}
18784
18785#[test]
18786fn test_wrap_with_prefix() {
18787    assert_eq!(
18788        wrap_with_prefix(
18789            "# ".to_string(),
18790            "abcdefg".to_string(),
18791            4,
18792            NonZeroU32::new(4).unwrap(),
18793            false,
18794        ),
18795        "# abcdefg"
18796    );
18797    assert_eq!(
18798        wrap_with_prefix(
18799            "".to_string(),
18800            "\thello world".to_string(),
18801            8,
18802            NonZeroU32::new(4).unwrap(),
18803            false,
18804        ),
18805        "hello\nworld"
18806    );
18807    assert_eq!(
18808        wrap_with_prefix(
18809            "// ".to_string(),
18810            "xx \nyy zz aa bb cc".to_string(),
18811            12,
18812            NonZeroU32::new(4).unwrap(),
18813            false,
18814        ),
18815        "// xx yy zz\n// aa bb cc"
18816    );
18817    assert_eq!(
18818        wrap_with_prefix(
18819            String::new(),
18820            "这是什么 \n 钢笔".to_string(),
18821            3,
18822            NonZeroU32::new(4).unwrap(),
18823            false,
18824        ),
18825        "这是什\n么 钢\n"
18826    );
18827}
18828
18829pub trait CollaborationHub {
18830    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
18831    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
18832    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
18833}
18834
18835impl CollaborationHub for Entity<Project> {
18836    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
18837        self.read(cx).collaborators()
18838    }
18839
18840    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
18841        self.read(cx).user_store().read(cx).participant_indices()
18842    }
18843
18844    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
18845        let this = self.read(cx);
18846        let user_ids = this.collaborators().values().map(|c| c.user_id);
18847        this.user_store().read_with(cx, |user_store, cx| {
18848            user_store.participant_names(user_ids, cx)
18849        })
18850    }
18851}
18852
18853pub trait SemanticsProvider {
18854    fn hover(
18855        &self,
18856        buffer: &Entity<Buffer>,
18857        position: text::Anchor,
18858        cx: &mut App,
18859    ) -> Option<Task<Vec<project::Hover>>>;
18860
18861    fn inlay_hints(
18862        &self,
18863        buffer_handle: Entity<Buffer>,
18864        range: Range<text::Anchor>,
18865        cx: &mut App,
18866    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
18867
18868    fn resolve_inlay_hint(
18869        &self,
18870        hint: InlayHint,
18871        buffer_handle: Entity<Buffer>,
18872        server_id: LanguageServerId,
18873        cx: &mut App,
18874    ) -> Option<Task<anyhow::Result<InlayHint>>>;
18875
18876    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
18877
18878    fn document_highlights(
18879        &self,
18880        buffer: &Entity<Buffer>,
18881        position: text::Anchor,
18882        cx: &mut App,
18883    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
18884
18885    fn definitions(
18886        &self,
18887        buffer: &Entity<Buffer>,
18888        position: text::Anchor,
18889        kind: GotoDefinitionKind,
18890        cx: &mut App,
18891    ) -> Option<Task<Result<Vec<LocationLink>>>>;
18892
18893    fn range_for_rename(
18894        &self,
18895        buffer: &Entity<Buffer>,
18896        position: text::Anchor,
18897        cx: &mut App,
18898    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
18899
18900    fn perform_rename(
18901        &self,
18902        buffer: &Entity<Buffer>,
18903        position: text::Anchor,
18904        new_name: String,
18905        cx: &mut App,
18906    ) -> Option<Task<Result<ProjectTransaction>>>;
18907}
18908
18909pub trait CompletionProvider {
18910    fn completions(
18911        &self,
18912        excerpt_id: ExcerptId,
18913        buffer: &Entity<Buffer>,
18914        buffer_position: text::Anchor,
18915        trigger: CompletionContext,
18916        window: &mut Window,
18917        cx: &mut Context<Editor>,
18918    ) -> Task<Result<Option<Vec<Completion>>>>;
18919
18920    fn resolve_completions(
18921        &self,
18922        buffer: Entity<Buffer>,
18923        completion_indices: Vec<usize>,
18924        completions: Rc<RefCell<Box<[Completion]>>>,
18925        cx: &mut Context<Editor>,
18926    ) -> Task<Result<bool>>;
18927
18928    fn apply_additional_edits_for_completion(
18929        &self,
18930        _buffer: Entity<Buffer>,
18931        _completions: Rc<RefCell<Box<[Completion]>>>,
18932        _completion_index: usize,
18933        _push_to_history: bool,
18934        _cx: &mut Context<Editor>,
18935    ) -> Task<Result<Option<language::Transaction>>> {
18936        Task::ready(Ok(None))
18937    }
18938
18939    fn is_completion_trigger(
18940        &self,
18941        buffer: &Entity<Buffer>,
18942        position: language::Anchor,
18943        text: &str,
18944        trigger_in_words: bool,
18945        cx: &mut Context<Editor>,
18946    ) -> bool;
18947
18948    fn sort_completions(&self) -> bool {
18949        true
18950    }
18951
18952    fn filter_completions(&self) -> bool {
18953        true
18954    }
18955}
18956
18957pub trait CodeActionProvider {
18958    fn id(&self) -> Arc<str>;
18959
18960    fn code_actions(
18961        &self,
18962        buffer: &Entity<Buffer>,
18963        range: Range<text::Anchor>,
18964        window: &mut Window,
18965        cx: &mut App,
18966    ) -> Task<Result<Vec<CodeAction>>>;
18967
18968    fn apply_code_action(
18969        &self,
18970        buffer_handle: Entity<Buffer>,
18971        action: CodeAction,
18972        excerpt_id: ExcerptId,
18973        push_to_history: bool,
18974        window: &mut Window,
18975        cx: &mut App,
18976    ) -> Task<Result<ProjectTransaction>>;
18977}
18978
18979impl CodeActionProvider for Entity<Project> {
18980    fn id(&self) -> Arc<str> {
18981        "project".into()
18982    }
18983
18984    fn code_actions(
18985        &self,
18986        buffer: &Entity<Buffer>,
18987        range: Range<text::Anchor>,
18988        _window: &mut Window,
18989        cx: &mut App,
18990    ) -> Task<Result<Vec<CodeAction>>> {
18991        self.update(cx, |project, cx| {
18992            let code_lens = project.code_lens(buffer, range.clone(), cx);
18993            let code_actions = project.code_actions(buffer, range, None, cx);
18994            cx.background_spawn(async move {
18995                let (code_lens, code_actions) = join(code_lens, code_actions).await;
18996                Ok(code_lens
18997                    .context("code lens fetch")?
18998                    .into_iter()
18999                    .chain(code_actions.context("code action fetch")?)
19000                    .collect())
19001            })
19002        })
19003    }
19004
19005    fn apply_code_action(
19006        &self,
19007        buffer_handle: Entity<Buffer>,
19008        action: CodeAction,
19009        _excerpt_id: ExcerptId,
19010        push_to_history: bool,
19011        _window: &mut Window,
19012        cx: &mut App,
19013    ) -> Task<Result<ProjectTransaction>> {
19014        self.update(cx, |project, cx| {
19015            project.apply_code_action(buffer_handle, action, push_to_history, cx)
19016        })
19017    }
19018}
19019
19020fn snippet_completions(
19021    project: &Project,
19022    buffer: &Entity<Buffer>,
19023    buffer_position: text::Anchor,
19024    cx: &mut App,
19025) -> Task<Result<Vec<Completion>>> {
19026    let languages = buffer.read(cx).languages_at(buffer_position);
19027    let snippet_store = project.snippets().read(cx);
19028
19029    let scopes: Vec<_> = languages
19030        .iter()
19031        .filter_map(|language| {
19032            let language_name = language.lsp_id();
19033            let snippets = snippet_store.snippets_for(Some(language_name), cx);
19034
19035            if snippets.is_empty() {
19036                None
19037            } else {
19038                Some((language.default_scope(), snippets))
19039            }
19040        })
19041        .collect();
19042
19043    if scopes.is_empty() {
19044        return Task::ready(Ok(vec![]));
19045    }
19046
19047    let snapshot = buffer.read(cx).text_snapshot();
19048    let chars: String = snapshot
19049        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
19050        .collect();
19051    let executor = cx.background_executor().clone();
19052
19053    cx.background_spawn(async move {
19054        let mut all_results: Vec<Completion> = Vec::new();
19055        for (scope, snippets) in scopes.into_iter() {
19056            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
19057            let mut last_word = chars
19058                .chars()
19059                .take_while(|c| classifier.is_word(*c))
19060                .collect::<String>();
19061            last_word = last_word.chars().rev().collect();
19062
19063            if last_word.is_empty() {
19064                return Ok(vec![]);
19065            }
19066
19067            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
19068            let to_lsp = |point: &text::Anchor| {
19069                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
19070                point_to_lsp(end)
19071            };
19072            let lsp_end = to_lsp(&buffer_position);
19073
19074            let candidates = snippets
19075                .iter()
19076                .enumerate()
19077                .flat_map(|(ix, snippet)| {
19078                    snippet
19079                        .prefix
19080                        .iter()
19081                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
19082                })
19083                .collect::<Vec<StringMatchCandidate>>();
19084
19085            let mut matches = fuzzy::match_strings(
19086                &candidates,
19087                &last_word,
19088                last_word.chars().any(|c| c.is_uppercase()),
19089                100,
19090                &Default::default(),
19091                executor.clone(),
19092            )
19093            .await;
19094
19095            // Remove all candidates where the query's start does not match the start of any word in the candidate
19096            if let Some(query_start) = last_word.chars().next() {
19097                matches.retain(|string_match| {
19098                    split_words(&string_match.string).any(|word| {
19099                        // Check that the first codepoint of the word as lowercase matches the first
19100                        // codepoint of the query as lowercase
19101                        word.chars()
19102                            .flat_map(|codepoint| codepoint.to_lowercase())
19103                            .zip(query_start.to_lowercase())
19104                            .all(|(word_cp, query_cp)| word_cp == query_cp)
19105                    })
19106                });
19107            }
19108
19109            let matched_strings = matches
19110                .into_iter()
19111                .map(|m| m.string)
19112                .collect::<HashSet<_>>();
19113
19114            let mut result: Vec<Completion> = snippets
19115                .iter()
19116                .filter_map(|snippet| {
19117                    let matching_prefix = snippet
19118                        .prefix
19119                        .iter()
19120                        .find(|prefix| matched_strings.contains(*prefix))?;
19121                    let start = as_offset - last_word.len();
19122                    let start = snapshot.anchor_before(start);
19123                    let range = start..buffer_position;
19124                    let lsp_start = to_lsp(&start);
19125                    let lsp_range = lsp::Range {
19126                        start: lsp_start,
19127                        end: lsp_end,
19128                    };
19129                    Some(Completion {
19130                        replace_range: range,
19131                        new_text: snippet.body.clone(),
19132                        source: CompletionSource::Lsp {
19133                            insert_range: None,
19134                            server_id: LanguageServerId(usize::MAX),
19135                            resolved: true,
19136                            lsp_completion: Box::new(lsp::CompletionItem {
19137                                label: snippet.prefix.first().unwrap().clone(),
19138                                kind: Some(CompletionItemKind::SNIPPET),
19139                                label_details: snippet.description.as_ref().map(|description| {
19140                                    lsp::CompletionItemLabelDetails {
19141                                        detail: Some(description.clone()),
19142                                        description: None,
19143                                    }
19144                                }),
19145                                insert_text_format: Some(InsertTextFormat::SNIPPET),
19146                                text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
19147                                    lsp::InsertReplaceEdit {
19148                                        new_text: snippet.body.clone(),
19149                                        insert: lsp_range,
19150                                        replace: lsp_range,
19151                                    },
19152                                )),
19153                                filter_text: Some(snippet.body.clone()),
19154                                sort_text: Some(char::MAX.to_string()),
19155                                ..lsp::CompletionItem::default()
19156                            }),
19157                            lsp_defaults: None,
19158                        },
19159                        label: CodeLabel {
19160                            text: matching_prefix.clone(),
19161                            runs: Vec::new(),
19162                            filter_range: 0..matching_prefix.len(),
19163                        },
19164                        icon_path: None,
19165                        documentation: snippet.description.clone().map(|description| {
19166                            CompletionDocumentation::SingleLine(description.into())
19167                        }),
19168                        insert_text_mode: None,
19169                        confirm: None,
19170                    })
19171                })
19172                .collect();
19173
19174            all_results.append(&mut result);
19175        }
19176
19177        Ok(all_results)
19178    })
19179}
19180
19181impl CompletionProvider for Entity<Project> {
19182    fn completions(
19183        &self,
19184        _excerpt_id: ExcerptId,
19185        buffer: &Entity<Buffer>,
19186        buffer_position: text::Anchor,
19187        options: CompletionContext,
19188        _window: &mut Window,
19189        cx: &mut Context<Editor>,
19190    ) -> Task<Result<Option<Vec<Completion>>>> {
19191        self.update(cx, |project, cx| {
19192            let snippets = snippet_completions(project, buffer, buffer_position, cx);
19193            let project_completions = project.completions(buffer, buffer_position, options, cx);
19194            cx.background_spawn(async move {
19195                let snippets_completions = snippets.await?;
19196                match project_completions.await? {
19197                    Some(mut completions) => {
19198                        completions.extend(snippets_completions);
19199                        Ok(Some(completions))
19200                    }
19201                    None => {
19202                        if snippets_completions.is_empty() {
19203                            Ok(None)
19204                        } else {
19205                            Ok(Some(snippets_completions))
19206                        }
19207                    }
19208                }
19209            })
19210        })
19211    }
19212
19213    fn resolve_completions(
19214        &self,
19215        buffer: Entity<Buffer>,
19216        completion_indices: Vec<usize>,
19217        completions: Rc<RefCell<Box<[Completion]>>>,
19218        cx: &mut Context<Editor>,
19219    ) -> Task<Result<bool>> {
19220        self.update(cx, |project, cx| {
19221            project.lsp_store().update(cx, |lsp_store, cx| {
19222                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
19223            })
19224        })
19225    }
19226
19227    fn apply_additional_edits_for_completion(
19228        &self,
19229        buffer: Entity<Buffer>,
19230        completions: Rc<RefCell<Box<[Completion]>>>,
19231        completion_index: usize,
19232        push_to_history: bool,
19233        cx: &mut Context<Editor>,
19234    ) -> Task<Result<Option<language::Transaction>>> {
19235        self.update(cx, |project, cx| {
19236            project.lsp_store().update(cx, |lsp_store, cx| {
19237                lsp_store.apply_additional_edits_for_completion(
19238                    buffer,
19239                    completions,
19240                    completion_index,
19241                    push_to_history,
19242                    cx,
19243                )
19244            })
19245        })
19246    }
19247
19248    fn is_completion_trigger(
19249        &self,
19250        buffer: &Entity<Buffer>,
19251        position: language::Anchor,
19252        text: &str,
19253        trigger_in_words: bool,
19254        cx: &mut Context<Editor>,
19255    ) -> bool {
19256        let mut chars = text.chars();
19257        let char = if let Some(char) = chars.next() {
19258            char
19259        } else {
19260            return false;
19261        };
19262        if chars.next().is_some() {
19263            return false;
19264        }
19265
19266        let buffer = buffer.read(cx);
19267        let snapshot = buffer.snapshot();
19268        if !snapshot.settings_at(position, cx).show_completions_on_input {
19269            return false;
19270        }
19271        let classifier = snapshot.char_classifier_at(position).for_completion(true);
19272        if trigger_in_words && classifier.is_word(char) {
19273            return true;
19274        }
19275
19276        buffer.completion_triggers().contains(text)
19277    }
19278}
19279
19280impl SemanticsProvider for Entity<Project> {
19281    fn hover(
19282        &self,
19283        buffer: &Entity<Buffer>,
19284        position: text::Anchor,
19285        cx: &mut App,
19286    ) -> Option<Task<Vec<project::Hover>>> {
19287        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
19288    }
19289
19290    fn document_highlights(
19291        &self,
19292        buffer: &Entity<Buffer>,
19293        position: text::Anchor,
19294        cx: &mut App,
19295    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
19296        Some(self.update(cx, |project, cx| {
19297            project.document_highlights(buffer, position, cx)
19298        }))
19299    }
19300
19301    fn definitions(
19302        &self,
19303        buffer: &Entity<Buffer>,
19304        position: text::Anchor,
19305        kind: GotoDefinitionKind,
19306        cx: &mut App,
19307    ) -> Option<Task<Result<Vec<LocationLink>>>> {
19308        Some(self.update(cx, |project, cx| match kind {
19309            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
19310            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
19311            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
19312            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
19313        }))
19314    }
19315
19316    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
19317        // TODO: make this work for remote projects
19318        self.update(cx, |this, cx| {
19319            buffer.update(cx, |buffer, cx| {
19320                this.any_language_server_supports_inlay_hints(buffer, cx)
19321            })
19322        })
19323    }
19324
19325    fn inlay_hints(
19326        &self,
19327        buffer_handle: Entity<Buffer>,
19328        range: Range<text::Anchor>,
19329        cx: &mut App,
19330    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
19331        Some(self.update(cx, |project, cx| {
19332            project.inlay_hints(buffer_handle, range, cx)
19333        }))
19334    }
19335
19336    fn resolve_inlay_hint(
19337        &self,
19338        hint: InlayHint,
19339        buffer_handle: Entity<Buffer>,
19340        server_id: LanguageServerId,
19341        cx: &mut App,
19342    ) -> Option<Task<anyhow::Result<InlayHint>>> {
19343        Some(self.update(cx, |project, cx| {
19344            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
19345        }))
19346    }
19347
19348    fn range_for_rename(
19349        &self,
19350        buffer: &Entity<Buffer>,
19351        position: text::Anchor,
19352        cx: &mut App,
19353    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
19354        Some(self.update(cx, |project, cx| {
19355            let buffer = buffer.clone();
19356            let task = project.prepare_rename(buffer.clone(), position, cx);
19357            cx.spawn(async move |_, cx| {
19358                Ok(match task.await? {
19359                    PrepareRenameResponse::Success(range) => Some(range),
19360                    PrepareRenameResponse::InvalidPosition => None,
19361                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
19362                        // Fallback on using TreeSitter info to determine identifier range
19363                        buffer.update(cx, |buffer, _| {
19364                            let snapshot = buffer.snapshot();
19365                            let (range, kind) = snapshot.surrounding_word(position);
19366                            if kind != Some(CharKind::Word) {
19367                                return None;
19368                            }
19369                            Some(
19370                                snapshot.anchor_before(range.start)
19371                                    ..snapshot.anchor_after(range.end),
19372                            )
19373                        })?
19374                    }
19375                })
19376            })
19377        }))
19378    }
19379
19380    fn perform_rename(
19381        &self,
19382        buffer: &Entity<Buffer>,
19383        position: text::Anchor,
19384        new_name: String,
19385        cx: &mut App,
19386    ) -> Option<Task<Result<ProjectTransaction>>> {
19387        Some(self.update(cx, |project, cx| {
19388            project.perform_rename(buffer.clone(), position, new_name, cx)
19389        }))
19390    }
19391}
19392
19393fn inlay_hint_settings(
19394    location: Anchor,
19395    snapshot: &MultiBufferSnapshot,
19396    cx: &mut Context<Editor>,
19397) -> InlayHintSettings {
19398    let file = snapshot.file_at(location);
19399    let language = snapshot.language_at(location).map(|l| l.name());
19400    language_settings(language, file, cx).inlay_hints
19401}
19402
19403fn consume_contiguous_rows(
19404    contiguous_row_selections: &mut Vec<Selection<Point>>,
19405    selection: &Selection<Point>,
19406    display_map: &DisplaySnapshot,
19407    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
19408) -> (MultiBufferRow, MultiBufferRow) {
19409    contiguous_row_selections.push(selection.clone());
19410    let start_row = MultiBufferRow(selection.start.row);
19411    let mut end_row = ending_row(selection, display_map);
19412
19413    while let Some(next_selection) = selections.peek() {
19414        if next_selection.start.row <= end_row.0 {
19415            end_row = ending_row(next_selection, display_map);
19416            contiguous_row_selections.push(selections.next().unwrap().clone());
19417        } else {
19418            break;
19419        }
19420    }
19421    (start_row, end_row)
19422}
19423
19424fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
19425    if next_selection.end.column > 0 || next_selection.is_empty() {
19426        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
19427    } else {
19428        MultiBufferRow(next_selection.end.row)
19429    }
19430}
19431
19432impl EditorSnapshot {
19433    pub fn remote_selections_in_range<'a>(
19434        &'a self,
19435        range: &'a Range<Anchor>,
19436        collaboration_hub: &dyn CollaborationHub,
19437        cx: &'a App,
19438    ) -> impl 'a + Iterator<Item = RemoteSelection> {
19439        let participant_names = collaboration_hub.user_names(cx);
19440        let participant_indices = collaboration_hub.user_participant_indices(cx);
19441        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
19442        let collaborators_by_replica_id = collaborators_by_peer_id
19443            .iter()
19444            .map(|(_, collaborator)| (collaborator.replica_id, collaborator))
19445            .collect::<HashMap<_, _>>();
19446        self.buffer_snapshot
19447            .selections_in_range(range, false)
19448            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
19449                let collaborator = collaborators_by_replica_id.get(&replica_id)?;
19450                let participant_index = participant_indices.get(&collaborator.user_id).copied();
19451                let user_name = participant_names.get(&collaborator.user_id).cloned();
19452                Some(RemoteSelection {
19453                    replica_id,
19454                    selection,
19455                    cursor_shape,
19456                    line_mode,
19457                    participant_index,
19458                    peer_id: collaborator.peer_id,
19459                    user_name,
19460                })
19461            })
19462    }
19463
19464    pub fn hunks_for_ranges(
19465        &self,
19466        ranges: impl IntoIterator<Item = Range<Point>>,
19467    ) -> Vec<MultiBufferDiffHunk> {
19468        let mut hunks = Vec::new();
19469        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
19470            HashMap::default();
19471        for query_range in ranges {
19472            let query_rows =
19473                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
19474            for hunk in self.buffer_snapshot.diff_hunks_in_range(
19475                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
19476            ) {
19477                // Include deleted hunks that are adjacent to the query range, because
19478                // otherwise they would be missed.
19479                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
19480                if hunk.status().is_deleted() {
19481                    intersects_range |= hunk.row_range.start == query_rows.end;
19482                    intersects_range |= hunk.row_range.end == query_rows.start;
19483                }
19484                if intersects_range {
19485                    if !processed_buffer_rows
19486                        .entry(hunk.buffer_id)
19487                        .or_default()
19488                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
19489                    {
19490                        continue;
19491                    }
19492                    hunks.push(hunk);
19493                }
19494            }
19495        }
19496
19497        hunks
19498    }
19499
19500    fn display_diff_hunks_for_rows<'a>(
19501        &'a self,
19502        display_rows: Range<DisplayRow>,
19503        folded_buffers: &'a HashSet<BufferId>,
19504    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
19505        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
19506        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
19507
19508        self.buffer_snapshot
19509            .diff_hunks_in_range(buffer_start..buffer_end)
19510            .filter_map(|hunk| {
19511                if folded_buffers.contains(&hunk.buffer_id) {
19512                    return None;
19513                }
19514
19515                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
19516                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
19517
19518                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
19519                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
19520
19521                let display_hunk = if hunk_display_start.column() != 0 {
19522                    DisplayDiffHunk::Folded {
19523                        display_row: hunk_display_start.row(),
19524                    }
19525                } else {
19526                    let mut end_row = hunk_display_end.row();
19527                    if hunk_display_end.column() > 0 {
19528                        end_row.0 += 1;
19529                    }
19530                    let is_created_file = hunk.is_created_file();
19531                    DisplayDiffHunk::Unfolded {
19532                        status: hunk.status(),
19533                        diff_base_byte_range: hunk.diff_base_byte_range,
19534                        display_row_range: hunk_display_start.row()..end_row,
19535                        multi_buffer_range: Anchor::range_in_buffer(
19536                            hunk.excerpt_id,
19537                            hunk.buffer_id,
19538                            hunk.buffer_range,
19539                        ),
19540                        is_created_file,
19541                    }
19542                };
19543
19544                Some(display_hunk)
19545            })
19546    }
19547
19548    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
19549        self.display_snapshot.buffer_snapshot.language_at(position)
19550    }
19551
19552    pub fn is_focused(&self) -> bool {
19553        self.is_focused
19554    }
19555
19556    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
19557        self.placeholder_text.as_ref()
19558    }
19559
19560    pub fn scroll_position(&self) -> gpui::Point<f32> {
19561        self.scroll_anchor.scroll_position(&self.display_snapshot)
19562    }
19563
19564    fn gutter_dimensions(
19565        &self,
19566        font_id: FontId,
19567        font_size: Pixels,
19568        max_line_number_width: Pixels,
19569        cx: &App,
19570    ) -> Option<GutterDimensions> {
19571        if !self.show_gutter {
19572            return None;
19573        }
19574
19575        let descent = cx.text_system().descent(font_id, font_size);
19576        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
19577        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
19578
19579        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
19580            matches!(
19581                ProjectSettings::get_global(cx).git.git_gutter,
19582                Some(GitGutterSetting::TrackedFiles)
19583            )
19584        });
19585        let gutter_settings = EditorSettings::get_global(cx).gutter;
19586        let show_line_numbers = self
19587            .show_line_numbers
19588            .unwrap_or(gutter_settings.line_numbers);
19589        let line_gutter_width = if show_line_numbers {
19590            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
19591            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
19592            max_line_number_width.max(min_width_for_number_on_gutter)
19593        } else {
19594            0.0.into()
19595        };
19596
19597        let show_code_actions = self
19598            .show_code_actions
19599            .unwrap_or(gutter_settings.code_actions);
19600
19601        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
19602        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
19603
19604        let git_blame_entries_width =
19605            self.git_blame_gutter_max_author_length
19606                .map(|max_author_length| {
19607                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19608                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
19609
19610                    /// The number of characters to dedicate to gaps and margins.
19611                    const SPACING_WIDTH: usize = 4;
19612
19613                    let max_char_count = max_author_length.min(renderer.max_author_length())
19614                        + ::git::SHORT_SHA_LENGTH
19615                        + MAX_RELATIVE_TIMESTAMP.len()
19616                        + SPACING_WIDTH;
19617
19618                    em_advance * max_char_count
19619                });
19620
19621        let is_singleton = self.buffer_snapshot.is_singleton();
19622
19623        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
19624        left_padding += if !is_singleton {
19625            em_width * 4.0
19626        } else if show_code_actions || show_runnables || show_breakpoints {
19627            em_width * 3.0
19628        } else if show_git_gutter && show_line_numbers {
19629            em_width * 2.0
19630        } else if show_git_gutter || show_line_numbers {
19631            em_width
19632        } else {
19633            px(0.)
19634        };
19635
19636        let shows_folds = is_singleton && gutter_settings.folds;
19637
19638        let right_padding = if shows_folds && show_line_numbers {
19639            em_width * 4.0
19640        } else if shows_folds || (!is_singleton && show_line_numbers) {
19641            em_width * 3.0
19642        } else if show_line_numbers {
19643            em_width
19644        } else {
19645            px(0.)
19646        };
19647
19648        Some(GutterDimensions {
19649            left_padding,
19650            right_padding,
19651            width: line_gutter_width + left_padding + right_padding,
19652            margin: -descent,
19653            git_blame_entries_width,
19654        })
19655    }
19656
19657    pub fn render_crease_toggle(
19658        &self,
19659        buffer_row: MultiBufferRow,
19660        row_contains_cursor: bool,
19661        editor: Entity<Editor>,
19662        window: &mut Window,
19663        cx: &mut App,
19664    ) -> Option<AnyElement> {
19665        let folded = self.is_line_folded(buffer_row);
19666        let mut is_foldable = false;
19667
19668        if let Some(crease) = self
19669            .crease_snapshot
19670            .query_row(buffer_row, &self.buffer_snapshot)
19671        {
19672            is_foldable = true;
19673            match crease {
19674                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
19675                    if let Some(render_toggle) = render_toggle {
19676                        let toggle_callback =
19677                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
19678                                if folded {
19679                                    editor.update(cx, |editor, cx| {
19680                                        editor.fold_at(buffer_row, window, cx)
19681                                    });
19682                                } else {
19683                                    editor.update(cx, |editor, cx| {
19684                                        editor.unfold_at(buffer_row, window, cx)
19685                                    });
19686                                }
19687                            });
19688                        return Some((render_toggle)(
19689                            buffer_row,
19690                            folded,
19691                            toggle_callback,
19692                            window,
19693                            cx,
19694                        ));
19695                    }
19696                }
19697            }
19698        }
19699
19700        is_foldable |= self.starts_indent(buffer_row);
19701
19702        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
19703            Some(
19704                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
19705                    .toggle_state(folded)
19706                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
19707                        if folded {
19708                            this.unfold_at(buffer_row, window, cx);
19709                        } else {
19710                            this.fold_at(buffer_row, window, cx);
19711                        }
19712                    }))
19713                    .into_any_element(),
19714            )
19715        } else {
19716            None
19717        }
19718    }
19719
19720    pub fn render_crease_trailer(
19721        &self,
19722        buffer_row: MultiBufferRow,
19723        window: &mut Window,
19724        cx: &mut App,
19725    ) -> Option<AnyElement> {
19726        let folded = self.is_line_folded(buffer_row);
19727        if let Crease::Inline { render_trailer, .. } = self
19728            .crease_snapshot
19729            .query_row(buffer_row, &self.buffer_snapshot)?
19730        {
19731            let render_trailer = render_trailer.as_ref()?;
19732            Some(render_trailer(buffer_row, folded, window, cx))
19733        } else {
19734            None
19735        }
19736    }
19737}
19738
19739impl Deref for EditorSnapshot {
19740    type Target = DisplaySnapshot;
19741
19742    fn deref(&self) -> &Self::Target {
19743        &self.display_snapshot
19744    }
19745}
19746
19747#[derive(Clone, Debug, PartialEq, Eq)]
19748pub enum EditorEvent {
19749    InputIgnored {
19750        text: Arc<str>,
19751    },
19752    InputHandled {
19753        utf16_range_to_replace: Option<Range<isize>>,
19754        text: Arc<str>,
19755    },
19756    ExcerptsAdded {
19757        buffer: Entity<Buffer>,
19758        predecessor: ExcerptId,
19759        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
19760    },
19761    ExcerptsRemoved {
19762        ids: Vec<ExcerptId>,
19763    },
19764    BufferFoldToggled {
19765        ids: Vec<ExcerptId>,
19766        folded: bool,
19767    },
19768    ExcerptsEdited {
19769        ids: Vec<ExcerptId>,
19770    },
19771    ExcerptsExpanded {
19772        ids: Vec<ExcerptId>,
19773    },
19774    BufferEdited,
19775    Edited {
19776        transaction_id: clock::Lamport,
19777    },
19778    Reparsed(BufferId),
19779    Focused,
19780    FocusedIn,
19781    Blurred,
19782    DirtyChanged,
19783    Saved,
19784    TitleChanged,
19785    DiffBaseChanged,
19786    SelectionsChanged {
19787        local: bool,
19788    },
19789    ScrollPositionChanged {
19790        local: bool,
19791        autoscroll: bool,
19792    },
19793    Closed,
19794    TransactionUndone {
19795        transaction_id: clock::Lamport,
19796    },
19797    TransactionBegun {
19798        transaction_id: clock::Lamport,
19799    },
19800    Reloaded,
19801    CursorShapeChanged,
19802    PushedToNavHistory {
19803        anchor: Anchor,
19804        is_deactivate: bool,
19805    },
19806}
19807
19808impl EventEmitter<EditorEvent> for Editor {}
19809
19810impl Focusable for Editor {
19811    fn focus_handle(&self, _cx: &App) -> FocusHandle {
19812        self.focus_handle.clone()
19813    }
19814}
19815
19816impl Render for Editor {
19817    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
19818        let settings = ThemeSettings::get_global(cx);
19819
19820        let mut text_style = match self.mode {
19821            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
19822                color: cx.theme().colors().editor_foreground,
19823                font_family: settings.ui_font.family.clone(),
19824                font_features: settings.ui_font.features.clone(),
19825                font_fallbacks: settings.ui_font.fallbacks.clone(),
19826                font_size: rems(0.875).into(),
19827                font_weight: settings.ui_font.weight,
19828                line_height: relative(settings.buffer_line_height.value()),
19829                ..Default::default()
19830            },
19831            EditorMode::Full { .. } => TextStyle {
19832                color: cx.theme().colors().editor_foreground,
19833                font_family: settings.buffer_font.family.clone(),
19834                font_features: settings.buffer_font.features.clone(),
19835                font_fallbacks: settings.buffer_font.fallbacks.clone(),
19836                font_size: settings.buffer_font_size(cx).into(),
19837                font_weight: settings.buffer_font.weight,
19838                line_height: relative(settings.buffer_line_height.value()),
19839                ..Default::default()
19840            },
19841        };
19842        if let Some(text_style_refinement) = &self.text_style_refinement {
19843            text_style.refine(text_style_refinement)
19844        }
19845
19846        let background = match self.mode {
19847            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
19848            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
19849            EditorMode::Full { .. } => cx.theme().colors().editor_background,
19850        };
19851
19852        EditorElement::new(
19853            &cx.entity(),
19854            EditorStyle {
19855                background,
19856                local_player: cx.theme().players().local(),
19857                text: text_style,
19858                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
19859                syntax: cx.theme().syntax().clone(),
19860                status: cx.theme().status().clone(),
19861                inlay_hints_style: make_inlay_hints_style(cx),
19862                inline_completion_styles: make_suggestion_styles(cx),
19863                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
19864            },
19865        )
19866    }
19867}
19868
19869impl EntityInputHandler for Editor {
19870    fn text_for_range(
19871        &mut self,
19872        range_utf16: Range<usize>,
19873        adjusted_range: &mut Option<Range<usize>>,
19874        _: &mut Window,
19875        cx: &mut Context<Self>,
19876    ) -> Option<String> {
19877        let snapshot = self.buffer.read(cx).read(cx);
19878        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
19879        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
19880        if (start.0..end.0) != range_utf16 {
19881            adjusted_range.replace(start.0..end.0);
19882        }
19883        Some(snapshot.text_for_range(start..end).collect())
19884    }
19885
19886    fn selected_text_range(
19887        &mut self,
19888        ignore_disabled_input: bool,
19889        _: &mut Window,
19890        cx: &mut Context<Self>,
19891    ) -> Option<UTF16Selection> {
19892        // Prevent the IME menu from appearing when holding down an alphabetic key
19893        // while input is disabled.
19894        if !ignore_disabled_input && !self.input_enabled {
19895            return None;
19896        }
19897
19898        let selection = self.selections.newest::<OffsetUtf16>(cx);
19899        let range = selection.range();
19900
19901        Some(UTF16Selection {
19902            range: range.start.0..range.end.0,
19903            reversed: selection.reversed,
19904        })
19905    }
19906
19907    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
19908        let snapshot = self.buffer.read(cx).read(cx);
19909        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
19910        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
19911    }
19912
19913    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19914        self.clear_highlights::<InputComposition>(cx);
19915        self.ime_transaction.take();
19916    }
19917
19918    fn replace_text_in_range(
19919        &mut self,
19920        range_utf16: Option<Range<usize>>,
19921        text: &str,
19922        window: &mut Window,
19923        cx: &mut Context<Self>,
19924    ) {
19925        if !self.input_enabled {
19926            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19927            return;
19928        }
19929
19930        self.transact(window, cx, |this, window, cx| {
19931            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
19932                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
19933                Some(this.selection_replacement_ranges(range_utf16, cx))
19934            } else {
19935                this.marked_text_ranges(cx)
19936            };
19937
19938            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
19939                let newest_selection_id = this.selections.newest_anchor().id;
19940                this.selections
19941                    .all::<OffsetUtf16>(cx)
19942                    .iter()
19943                    .zip(ranges_to_replace.iter())
19944                    .find_map(|(selection, range)| {
19945                        if selection.id == newest_selection_id {
19946                            Some(
19947                                (range.start.0 as isize - selection.head().0 as isize)
19948                                    ..(range.end.0 as isize - selection.head().0 as isize),
19949                            )
19950                        } else {
19951                            None
19952                        }
19953                    })
19954            });
19955
19956            cx.emit(EditorEvent::InputHandled {
19957                utf16_range_to_replace: range_to_replace,
19958                text: text.into(),
19959            });
19960
19961            if let Some(new_selected_ranges) = new_selected_ranges {
19962                this.change_selections(None, window, cx, |selections| {
19963                    selections.select_ranges(new_selected_ranges)
19964                });
19965                this.backspace(&Default::default(), window, cx);
19966            }
19967
19968            this.handle_input(text, window, cx);
19969        });
19970
19971        if let Some(transaction) = self.ime_transaction {
19972            self.buffer.update(cx, |buffer, cx| {
19973                buffer.group_until_transaction(transaction, cx);
19974            });
19975        }
19976
19977        self.unmark_text(window, cx);
19978    }
19979
19980    fn replace_and_mark_text_in_range(
19981        &mut self,
19982        range_utf16: Option<Range<usize>>,
19983        text: &str,
19984        new_selected_range_utf16: Option<Range<usize>>,
19985        window: &mut Window,
19986        cx: &mut Context<Self>,
19987    ) {
19988        if !self.input_enabled {
19989            return;
19990        }
19991
19992        let transaction = self.transact(window, cx, |this, window, cx| {
19993            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
19994                let snapshot = this.buffer.read(cx).read(cx);
19995                if let Some(relative_range_utf16) = range_utf16.as_ref() {
19996                    for marked_range in &mut marked_ranges {
19997                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
19998                        marked_range.start.0 += relative_range_utf16.start;
19999                        marked_range.start =
20000                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
20001                        marked_range.end =
20002                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
20003                    }
20004                }
20005                Some(marked_ranges)
20006            } else if let Some(range_utf16) = range_utf16 {
20007                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20008                Some(this.selection_replacement_ranges(range_utf16, cx))
20009            } else {
20010                None
20011            };
20012
20013            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
20014                let newest_selection_id = this.selections.newest_anchor().id;
20015                this.selections
20016                    .all::<OffsetUtf16>(cx)
20017                    .iter()
20018                    .zip(ranges_to_replace.iter())
20019                    .find_map(|(selection, range)| {
20020                        if selection.id == newest_selection_id {
20021                            Some(
20022                                (range.start.0 as isize - selection.head().0 as isize)
20023                                    ..(range.end.0 as isize - selection.head().0 as isize),
20024                            )
20025                        } else {
20026                            None
20027                        }
20028                    })
20029            });
20030
20031            cx.emit(EditorEvent::InputHandled {
20032                utf16_range_to_replace: range_to_replace,
20033                text: text.into(),
20034            });
20035
20036            if let Some(ranges) = ranges_to_replace {
20037                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
20038            }
20039
20040            let marked_ranges = {
20041                let snapshot = this.buffer.read(cx).read(cx);
20042                this.selections
20043                    .disjoint_anchors()
20044                    .iter()
20045                    .map(|selection| {
20046                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
20047                    })
20048                    .collect::<Vec<_>>()
20049            };
20050
20051            if text.is_empty() {
20052                this.unmark_text(window, cx);
20053            } else {
20054                this.highlight_text::<InputComposition>(
20055                    marked_ranges.clone(),
20056                    HighlightStyle {
20057                        underline: Some(UnderlineStyle {
20058                            thickness: px(1.),
20059                            color: None,
20060                            wavy: false,
20061                        }),
20062                        ..Default::default()
20063                    },
20064                    cx,
20065                );
20066            }
20067
20068            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
20069            let use_autoclose = this.use_autoclose;
20070            let use_auto_surround = this.use_auto_surround;
20071            this.set_use_autoclose(false);
20072            this.set_use_auto_surround(false);
20073            this.handle_input(text, window, cx);
20074            this.set_use_autoclose(use_autoclose);
20075            this.set_use_auto_surround(use_auto_surround);
20076
20077            if let Some(new_selected_range) = new_selected_range_utf16 {
20078                let snapshot = this.buffer.read(cx).read(cx);
20079                let new_selected_ranges = marked_ranges
20080                    .into_iter()
20081                    .map(|marked_range| {
20082                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
20083                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
20084                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
20085                        snapshot.clip_offset_utf16(new_start, Bias::Left)
20086                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
20087                    })
20088                    .collect::<Vec<_>>();
20089
20090                drop(snapshot);
20091                this.change_selections(None, window, cx, |selections| {
20092                    selections.select_ranges(new_selected_ranges)
20093                });
20094            }
20095        });
20096
20097        self.ime_transaction = self.ime_transaction.or(transaction);
20098        if let Some(transaction) = self.ime_transaction {
20099            self.buffer.update(cx, |buffer, cx| {
20100                buffer.group_until_transaction(transaction, cx);
20101            });
20102        }
20103
20104        if self.text_highlights::<InputComposition>(cx).is_none() {
20105            self.ime_transaction.take();
20106        }
20107    }
20108
20109    fn bounds_for_range(
20110        &mut self,
20111        range_utf16: Range<usize>,
20112        element_bounds: gpui::Bounds<Pixels>,
20113        window: &mut Window,
20114        cx: &mut Context<Self>,
20115    ) -> Option<gpui::Bounds<Pixels>> {
20116        let text_layout_details = self.text_layout_details(window);
20117        let gpui::Size {
20118            width: em_width,
20119            height: line_height,
20120        } = self.character_size(window);
20121
20122        let snapshot = self.snapshot(window, cx);
20123        let scroll_position = snapshot.scroll_position();
20124        let scroll_left = scroll_position.x * em_width;
20125
20126        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
20127        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
20128            + self.gutter_dimensions.width
20129            + self.gutter_dimensions.margin;
20130        let y = line_height * (start.row().as_f32() - scroll_position.y);
20131
20132        Some(Bounds {
20133            origin: element_bounds.origin + point(x, y),
20134            size: size(em_width, line_height),
20135        })
20136    }
20137
20138    fn character_index_for_point(
20139        &mut self,
20140        point: gpui::Point<Pixels>,
20141        _window: &mut Window,
20142        _cx: &mut Context<Self>,
20143    ) -> Option<usize> {
20144        let position_map = self.last_position_map.as_ref()?;
20145        if !position_map.text_hitbox.contains(&point) {
20146            return None;
20147        }
20148        let display_point = position_map.point_for_position(point).previous_valid;
20149        let anchor = position_map
20150            .snapshot
20151            .display_point_to_anchor(display_point, Bias::Left);
20152        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
20153        Some(utf16_offset.0)
20154    }
20155}
20156
20157trait SelectionExt {
20158    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
20159    fn spanned_rows(
20160        &self,
20161        include_end_if_at_line_start: bool,
20162        map: &DisplaySnapshot,
20163    ) -> Range<MultiBufferRow>;
20164}
20165
20166impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
20167    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
20168        let start = self
20169            .start
20170            .to_point(&map.buffer_snapshot)
20171            .to_display_point(map);
20172        let end = self
20173            .end
20174            .to_point(&map.buffer_snapshot)
20175            .to_display_point(map);
20176        if self.reversed {
20177            end..start
20178        } else {
20179            start..end
20180        }
20181    }
20182
20183    fn spanned_rows(
20184        &self,
20185        include_end_if_at_line_start: bool,
20186        map: &DisplaySnapshot,
20187    ) -> Range<MultiBufferRow> {
20188        let start = self.start.to_point(&map.buffer_snapshot);
20189        let mut end = self.end.to_point(&map.buffer_snapshot);
20190        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
20191            end.row -= 1;
20192        }
20193
20194        let buffer_start = map.prev_line_boundary(start).0;
20195        let buffer_end = map.next_line_boundary(end).0;
20196        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
20197    }
20198}
20199
20200impl<T: InvalidationRegion> InvalidationStack<T> {
20201    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
20202    where
20203        S: Clone + ToOffset,
20204    {
20205        while let Some(region) = self.last() {
20206            let all_selections_inside_invalidation_ranges =
20207                if selections.len() == region.ranges().len() {
20208                    selections
20209                        .iter()
20210                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
20211                        .all(|(selection, invalidation_range)| {
20212                            let head = selection.head().to_offset(buffer);
20213                            invalidation_range.start <= head && invalidation_range.end >= head
20214                        })
20215                } else {
20216                    false
20217                };
20218
20219            if all_selections_inside_invalidation_ranges {
20220                break;
20221            } else {
20222                self.pop();
20223            }
20224        }
20225    }
20226}
20227
20228impl<T> Default for InvalidationStack<T> {
20229    fn default() -> Self {
20230        Self(Default::default())
20231    }
20232}
20233
20234impl<T> Deref for InvalidationStack<T> {
20235    type Target = Vec<T>;
20236
20237    fn deref(&self) -> &Self::Target {
20238        &self.0
20239    }
20240}
20241
20242impl<T> DerefMut for InvalidationStack<T> {
20243    fn deref_mut(&mut self) -> &mut Self::Target {
20244        &mut self.0
20245    }
20246}
20247
20248impl InvalidationRegion for SnippetState {
20249    fn ranges(&self) -> &[Range<Anchor>] {
20250        &self.ranges[self.active_index]
20251    }
20252}
20253
20254fn inline_completion_edit_text(
20255    current_snapshot: &BufferSnapshot,
20256    edits: &[(Range<Anchor>, String)],
20257    edit_preview: &EditPreview,
20258    include_deletions: bool,
20259    cx: &App,
20260) -> HighlightedText {
20261    let edits = edits
20262        .iter()
20263        .map(|(anchor, text)| {
20264            (
20265                anchor.start.text_anchor..anchor.end.text_anchor,
20266                text.clone(),
20267            )
20268        })
20269        .collect::<Vec<_>>();
20270
20271    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
20272}
20273
20274pub fn diagnostic_style(severity: DiagnosticSeverity, colors: &StatusColors) -> Hsla {
20275    match severity {
20276        DiagnosticSeverity::ERROR => colors.error,
20277        DiagnosticSeverity::WARNING => colors.warning,
20278        DiagnosticSeverity::INFORMATION => colors.info,
20279        DiagnosticSeverity::HINT => colors.info,
20280        _ => colors.ignored,
20281    }
20282}
20283
20284pub fn styled_runs_for_code_label<'a>(
20285    label: &'a CodeLabel,
20286    syntax_theme: &'a theme::SyntaxTheme,
20287) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
20288    let fade_out = HighlightStyle {
20289        fade_out: Some(0.35),
20290        ..Default::default()
20291    };
20292
20293    let mut prev_end = label.filter_range.end;
20294    label
20295        .runs
20296        .iter()
20297        .enumerate()
20298        .flat_map(move |(ix, (range, highlight_id))| {
20299            let style = if let Some(style) = highlight_id.style(syntax_theme) {
20300                style
20301            } else {
20302                return Default::default();
20303            };
20304            let mut muted_style = style;
20305            muted_style.highlight(fade_out);
20306
20307            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
20308            if range.start >= label.filter_range.end {
20309                if range.start > prev_end {
20310                    runs.push((prev_end..range.start, fade_out));
20311                }
20312                runs.push((range.clone(), muted_style));
20313            } else if range.end <= label.filter_range.end {
20314                runs.push((range.clone(), style));
20315            } else {
20316                runs.push((range.start..label.filter_range.end, style));
20317                runs.push((label.filter_range.end..range.end, muted_style));
20318            }
20319            prev_end = cmp::max(prev_end, range.end);
20320
20321            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
20322                runs.push((prev_end..label.text.len(), fade_out));
20323            }
20324
20325            runs
20326        })
20327}
20328
20329pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
20330    let mut prev_index = 0;
20331    let mut prev_codepoint: Option<char> = None;
20332    text.char_indices()
20333        .chain([(text.len(), '\0')])
20334        .filter_map(move |(index, codepoint)| {
20335            let prev_codepoint = prev_codepoint.replace(codepoint)?;
20336            let is_boundary = index == text.len()
20337                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
20338                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
20339            if is_boundary {
20340                let chunk = &text[prev_index..index];
20341                prev_index = index;
20342                Some(chunk)
20343            } else {
20344                None
20345            }
20346        })
20347}
20348
20349pub trait RangeToAnchorExt: Sized {
20350    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
20351
20352    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
20353        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
20354        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
20355    }
20356}
20357
20358impl<T: ToOffset> RangeToAnchorExt for Range<T> {
20359    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
20360        let start_offset = self.start.to_offset(snapshot);
20361        let end_offset = self.end.to_offset(snapshot);
20362        if start_offset == end_offset {
20363            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
20364        } else {
20365            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
20366        }
20367    }
20368}
20369
20370pub trait RowExt {
20371    fn as_f32(&self) -> f32;
20372
20373    fn next_row(&self) -> Self;
20374
20375    fn previous_row(&self) -> Self;
20376
20377    fn minus(&self, other: Self) -> u32;
20378}
20379
20380impl RowExt for DisplayRow {
20381    fn as_f32(&self) -> f32 {
20382        self.0 as f32
20383    }
20384
20385    fn next_row(&self) -> Self {
20386        Self(self.0 + 1)
20387    }
20388
20389    fn previous_row(&self) -> Self {
20390        Self(self.0.saturating_sub(1))
20391    }
20392
20393    fn minus(&self, other: Self) -> u32 {
20394        self.0 - other.0
20395    }
20396}
20397
20398impl RowExt for MultiBufferRow {
20399    fn as_f32(&self) -> f32 {
20400        self.0 as f32
20401    }
20402
20403    fn next_row(&self) -> Self {
20404        Self(self.0 + 1)
20405    }
20406
20407    fn previous_row(&self) -> Self {
20408        Self(self.0.saturating_sub(1))
20409    }
20410
20411    fn minus(&self, other: Self) -> u32 {
20412        self.0 - other.0
20413    }
20414}
20415
20416trait RowRangeExt {
20417    type Row;
20418
20419    fn len(&self) -> usize;
20420
20421    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
20422}
20423
20424impl RowRangeExt for Range<MultiBufferRow> {
20425    type Row = MultiBufferRow;
20426
20427    fn len(&self) -> usize {
20428        (self.end.0 - self.start.0) as usize
20429    }
20430
20431    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
20432        (self.start.0..self.end.0).map(MultiBufferRow)
20433    }
20434}
20435
20436impl RowRangeExt for Range<DisplayRow> {
20437    type Row = DisplayRow;
20438
20439    fn len(&self) -> usize {
20440        (self.end.0 - self.start.0) as usize
20441    }
20442
20443    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
20444        (self.start.0..self.end.0).map(DisplayRow)
20445    }
20446}
20447
20448/// If select range has more than one line, we
20449/// just point the cursor to range.start.
20450fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
20451    if range.start.row == range.end.row {
20452        range
20453    } else {
20454        range.start..range.start
20455    }
20456}
20457pub struct KillRing(ClipboardItem);
20458impl Global for KillRing {}
20459
20460const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
20461
20462enum BreakpointPromptEditAction {
20463    Log,
20464    Condition,
20465    HitCondition,
20466}
20467
20468struct BreakpointPromptEditor {
20469    pub(crate) prompt: Entity<Editor>,
20470    editor: WeakEntity<Editor>,
20471    breakpoint_anchor: Anchor,
20472    breakpoint: Breakpoint,
20473    edit_action: BreakpointPromptEditAction,
20474    block_ids: HashSet<CustomBlockId>,
20475    gutter_dimensions: Arc<Mutex<GutterDimensions>>,
20476    _subscriptions: Vec<Subscription>,
20477}
20478
20479impl BreakpointPromptEditor {
20480    const MAX_LINES: u8 = 4;
20481
20482    fn new(
20483        editor: WeakEntity<Editor>,
20484        breakpoint_anchor: Anchor,
20485        breakpoint: Breakpoint,
20486        edit_action: BreakpointPromptEditAction,
20487        window: &mut Window,
20488        cx: &mut Context<Self>,
20489    ) -> Self {
20490        let base_text = match edit_action {
20491            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
20492            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
20493            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
20494        }
20495        .map(|msg| msg.to_string())
20496        .unwrap_or_default();
20497
20498        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
20499        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
20500
20501        let prompt = cx.new(|cx| {
20502            let mut prompt = Editor::new(
20503                EditorMode::AutoHeight {
20504                    max_lines: Self::MAX_LINES as usize,
20505                },
20506                buffer,
20507                None,
20508                window,
20509                cx,
20510            );
20511            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
20512            prompt.set_show_cursor_when_unfocused(false, cx);
20513            prompt.set_placeholder_text(
20514                match edit_action {
20515                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
20516                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
20517                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
20518                },
20519                cx,
20520            );
20521
20522            prompt
20523        });
20524
20525        Self {
20526            prompt,
20527            editor,
20528            breakpoint_anchor,
20529            breakpoint,
20530            edit_action,
20531            gutter_dimensions: Arc::new(Mutex::new(GutterDimensions::default())),
20532            block_ids: Default::default(),
20533            _subscriptions: vec![],
20534        }
20535    }
20536
20537    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
20538        self.block_ids.extend(block_ids)
20539    }
20540
20541    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
20542        if let Some(editor) = self.editor.upgrade() {
20543            let message = self
20544                .prompt
20545                .read(cx)
20546                .buffer
20547                .read(cx)
20548                .as_singleton()
20549                .expect("A multi buffer in breakpoint prompt isn't possible")
20550                .read(cx)
20551                .as_rope()
20552                .to_string();
20553
20554            editor.update(cx, |editor, cx| {
20555                editor.edit_breakpoint_at_anchor(
20556                    self.breakpoint_anchor,
20557                    self.breakpoint.clone(),
20558                    match self.edit_action {
20559                        BreakpointPromptEditAction::Log => {
20560                            BreakpointEditAction::EditLogMessage(message.into())
20561                        }
20562                        BreakpointPromptEditAction::Condition => {
20563                            BreakpointEditAction::EditCondition(message.into())
20564                        }
20565                        BreakpointPromptEditAction::HitCondition => {
20566                            BreakpointEditAction::EditHitCondition(message.into())
20567                        }
20568                    },
20569                    cx,
20570                );
20571
20572                editor.remove_blocks(self.block_ids.clone(), None, cx);
20573                cx.focus_self(window);
20574            });
20575        }
20576    }
20577
20578    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
20579        self.editor
20580            .update(cx, |editor, cx| {
20581                editor.remove_blocks(self.block_ids.clone(), None, cx);
20582                window.focus(&editor.focus_handle);
20583            })
20584            .log_err();
20585    }
20586
20587    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
20588        let settings = ThemeSettings::get_global(cx);
20589        let text_style = TextStyle {
20590            color: if self.prompt.read(cx).read_only(cx) {
20591                cx.theme().colors().text_disabled
20592            } else {
20593                cx.theme().colors().text
20594            },
20595            font_family: settings.buffer_font.family.clone(),
20596            font_fallbacks: settings.buffer_font.fallbacks.clone(),
20597            font_size: settings.buffer_font_size(cx).into(),
20598            font_weight: settings.buffer_font.weight,
20599            line_height: relative(settings.buffer_line_height.value()),
20600            ..Default::default()
20601        };
20602        EditorElement::new(
20603            &self.prompt,
20604            EditorStyle {
20605                background: cx.theme().colors().editor_background,
20606                local_player: cx.theme().players().local(),
20607                text: text_style,
20608                ..Default::default()
20609            },
20610        )
20611    }
20612}
20613
20614impl Render for BreakpointPromptEditor {
20615    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
20616        let gutter_dimensions = *self.gutter_dimensions.lock();
20617        h_flex()
20618            .key_context("Editor")
20619            .bg(cx.theme().colors().editor_background)
20620            .border_y_1()
20621            .border_color(cx.theme().status().info_border)
20622            .size_full()
20623            .py(window.line_height() / 2.5)
20624            .on_action(cx.listener(Self::confirm))
20625            .on_action(cx.listener(Self::cancel))
20626            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
20627            .child(div().flex_1().child(self.render_prompt_editor(cx)))
20628    }
20629}
20630
20631impl Focusable for BreakpointPromptEditor {
20632    fn focus_handle(&self, cx: &App) -> FocusHandle {
20633        self.prompt.focus_handle(cx)
20634    }
20635}
20636
20637fn all_edits_insertions_or_deletions(
20638    edits: &Vec<(Range<Anchor>, String)>,
20639    snapshot: &MultiBufferSnapshot,
20640) -> bool {
20641    let mut all_insertions = true;
20642    let mut all_deletions = true;
20643
20644    for (range, new_text) in edits.iter() {
20645        let range_is_empty = range.to_offset(&snapshot).is_empty();
20646        let text_is_empty = new_text.is_empty();
20647
20648        if range_is_empty != text_is_empty {
20649            if range_is_empty {
20650                all_deletions = false;
20651            } else {
20652                all_insertions = false;
20653            }
20654        } else {
20655            return false;
20656        }
20657
20658        if !all_insertions && !all_deletions {
20659            return false;
20660        }
20661    }
20662    all_insertions || all_deletions
20663}
20664
20665struct MissingEditPredictionKeybindingTooltip;
20666
20667impl Render for MissingEditPredictionKeybindingTooltip {
20668    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
20669        ui::tooltip_container(window, cx, |container, _, cx| {
20670            container
20671                .flex_shrink_0()
20672                .max_w_80()
20673                .min_h(rems_from_px(124.))
20674                .justify_between()
20675                .child(
20676                    v_flex()
20677                        .flex_1()
20678                        .text_ui_sm(cx)
20679                        .child(Label::new("Conflict with Accept Keybinding"))
20680                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
20681                )
20682                .child(
20683                    h_flex()
20684                        .pb_1()
20685                        .gap_1()
20686                        .items_end()
20687                        .w_full()
20688                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
20689                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
20690                        }))
20691                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
20692                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
20693                        })),
20694                )
20695        })
20696    }
20697}
20698
20699#[derive(Debug, Clone, Copy, PartialEq)]
20700pub struct LineHighlight {
20701    pub background: Background,
20702    pub border: Option<gpui::Hsla>,
20703}
20704
20705impl From<Hsla> for LineHighlight {
20706    fn from(hsla: Hsla) -> Self {
20707        Self {
20708            background: hsla.into(),
20709            border: None,
20710        }
20711    }
20712}
20713
20714impl From<Background> for LineHighlight {
20715    fn from(background: Background) -> Self {
20716        Self {
20717            background,
20718            border: None,
20719        }
20720    }
20721}
20722
20723fn render_diff_hunk_controls(
20724    row: u32,
20725    status: &DiffHunkStatus,
20726    hunk_range: Range<Anchor>,
20727    is_created_file: bool,
20728    line_height: Pixels,
20729    editor: &Entity<Editor>,
20730    _window: &mut Window,
20731    cx: &mut App,
20732) -> AnyElement {
20733    h_flex()
20734        .h(line_height)
20735        .mr_1()
20736        .gap_1()
20737        .px_0p5()
20738        .pb_1()
20739        .border_x_1()
20740        .border_b_1()
20741        .border_color(cx.theme().colors().border_variant)
20742        .rounded_b_lg()
20743        .bg(cx.theme().colors().editor_background)
20744        .gap_1()
20745        .occlude()
20746        .shadow_md()
20747        .child(if status.has_secondary_hunk() {
20748            Button::new(("stage", row as u64), "Stage")
20749                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
20750                .tooltip({
20751                    let focus_handle = editor.focus_handle(cx);
20752                    move |window, cx| {
20753                        Tooltip::for_action_in(
20754                            "Stage Hunk",
20755                            &::git::ToggleStaged,
20756                            &focus_handle,
20757                            window,
20758                            cx,
20759                        )
20760                    }
20761                })
20762                .on_click({
20763                    let editor = editor.clone();
20764                    move |_event, _window, cx| {
20765                        editor.update(cx, |editor, cx| {
20766                            editor.stage_or_unstage_diff_hunks(
20767                                true,
20768                                vec![hunk_range.start..hunk_range.start],
20769                                cx,
20770                            );
20771                        });
20772                    }
20773                })
20774        } else {
20775            Button::new(("unstage", row as u64), "Unstage")
20776                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
20777                .tooltip({
20778                    let focus_handle = editor.focus_handle(cx);
20779                    move |window, cx| {
20780                        Tooltip::for_action_in(
20781                            "Unstage Hunk",
20782                            &::git::ToggleStaged,
20783                            &focus_handle,
20784                            window,
20785                            cx,
20786                        )
20787                    }
20788                })
20789                .on_click({
20790                    let editor = editor.clone();
20791                    move |_event, _window, cx| {
20792                        editor.update(cx, |editor, cx| {
20793                            editor.stage_or_unstage_diff_hunks(
20794                                false,
20795                                vec![hunk_range.start..hunk_range.start],
20796                                cx,
20797                            );
20798                        });
20799                    }
20800                })
20801        })
20802        .child(
20803            Button::new(("restore", row as u64), "Restore")
20804                .tooltip({
20805                    let focus_handle = editor.focus_handle(cx);
20806                    move |window, cx| {
20807                        Tooltip::for_action_in(
20808                            "Restore Hunk",
20809                            &::git::Restore,
20810                            &focus_handle,
20811                            window,
20812                            cx,
20813                        )
20814                    }
20815                })
20816                .on_click({
20817                    let editor = editor.clone();
20818                    move |_event, window, cx| {
20819                        editor.update(cx, |editor, cx| {
20820                            let snapshot = editor.snapshot(window, cx);
20821                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
20822                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
20823                        });
20824                    }
20825                })
20826                .disabled(is_created_file),
20827        )
20828        .when(
20829            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
20830            |el| {
20831                el.child(
20832                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
20833                        .shape(IconButtonShape::Square)
20834                        .icon_size(IconSize::Small)
20835                        // .disabled(!has_multiple_hunks)
20836                        .tooltip({
20837                            let focus_handle = editor.focus_handle(cx);
20838                            move |window, cx| {
20839                                Tooltip::for_action_in(
20840                                    "Next Hunk",
20841                                    &GoToHunk,
20842                                    &focus_handle,
20843                                    window,
20844                                    cx,
20845                                )
20846                            }
20847                        })
20848                        .on_click({
20849                            let editor = editor.clone();
20850                            move |_event, window, cx| {
20851                                editor.update(cx, |editor, cx| {
20852                                    let snapshot = editor.snapshot(window, cx);
20853                                    let position =
20854                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
20855                                    editor.go_to_hunk_before_or_after_position(
20856                                        &snapshot,
20857                                        position,
20858                                        Direction::Next,
20859                                        window,
20860                                        cx,
20861                                    );
20862                                    editor.expand_selected_diff_hunks(cx);
20863                                });
20864                            }
20865                        }),
20866                )
20867                .child(
20868                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
20869                        .shape(IconButtonShape::Square)
20870                        .icon_size(IconSize::Small)
20871                        // .disabled(!has_multiple_hunks)
20872                        .tooltip({
20873                            let focus_handle = editor.focus_handle(cx);
20874                            move |window, cx| {
20875                                Tooltip::for_action_in(
20876                                    "Previous Hunk",
20877                                    &GoToPreviousHunk,
20878                                    &focus_handle,
20879                                    window,
20880                                    cx,
20881                                )
20882                            }
20883                        })
20884                        .on_click({
20885                            let editor = editor.clone();
20886                            move |_event, window, cx| {
20887                                editor.update(cx, |editor, cx| {
20888                                    let snapshot = editor.snapshot(window, cx);
20889                                    let point =
20890                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
20891                                    editor.go_to_hunk_before_or_after_position(
20892                                        &snapshot,
20893                                        point,
20894                                        Direction::Prev,
20895                                        window,
20896                                        cx,
20897                                    );
20898                                    editor.expand_selected_diff_hunks(cx);
20899                                });
20900                            }
20901                        }),
20902                )
20903            },
20904        )
20905        .into_any_element()
20906}